about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs48
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs102
-rw-r--r--library/alloc/src/boxed.rs6
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-add-auto.rs4
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-add-auto.stderr11
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-args.rs10
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-args.stderr44
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs4
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr10
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs15
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr136
-rw-r--r--tests/ui/mismatched_types/cast-rfc0401.rs2
-rw-r--r--tests/ui/mismatched_types/cast-rfc0401.stderr6
13 files changed, 331 insertions, 67 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index aa25e3adf28..2600c1fbff7 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2319,7 +2319,41 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
-                            (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => (),
+                            (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
+                                let src_tail = tcx.struct_tail_without_normalization(src.ty);
+                                let dst_tail = tcx.struct_tail_without_normalization(dst.ty);
+
+                                if let ty::Dynamic(..) = src_tail.kind()
+                                    && let ty::Dynamic(dst_tty, ..) = dst_tail.kind()
+                                    && dst_tty.principal().is_some()
+                                {
+                                    // Erase trait object lifetimes, to allow casts like `*mut dyn FnOnce()` -> `*mut dyn FnOnce() + 'static`.
+                                    let src_tail =
+                                        erase_single_trait_object_lifetime(tcx, src_tail);
+                                    let dst_tail =
+                                        erase_single_trait_object_lifetime(tcx, dst_tail);
+
+                                    let trait_ref = ty::TraitRef::new(
+                                        tcx,
+                                        tcx.require_lang_item(LangItem::Unsize, Some(span)),
+                                        [src_tail, dst_tail],
+                                    );
+
+                                    self.prove_trait_ref(
+                                        trait_ref,
+                                        location.to_locations(),
+                                        ConstraintCategory::Cast {
+                                            unsize_to: Some(tcx.fold_regions(dst_tail, |r, _| {
+                                                if let ty::ReVar(_) = r.kind() {
+                                                    tcx.lifetimes.re_erased
+                                                } else {
+                                                    r
+                                                }
+                                            })),
+                                        },
+                                    );
+                                }
+                            }
                             _ => {
                                 span_mirbug!(
                                     self,
@@ -2842,3 +2876,15 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
         Ok(output)
     }
 }
+
+fn erase_single_trait_object_lifetime<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+    let &ty::Dynamic(tty, region, dyn_kind @ ty::Dyn) = ty.kind() else {
+        bug!("expected trait object")
+    };
+
+    if region.is_erased() {
+        return ty;
+    }
+
+    tcx.mk_ty_from_kind(ty::Dynamic(tty, tcx.lifetimes.re_erased, dyn_kind))
+}
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 3207e4ea533..74be8529ec8 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -32,9 +32,9 @@ use super::FnCtxt;
 
 use crate::errors;
 use crate::type_error_struct;
-use hir::ExprKind;
 use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed};
-use rustc_hir as hir;
+use rustc_hir::{self as hir, ExprKind, LangItem};
+use rustc_infer::traits::Obligation;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
 use rustc_middle::mir::Mutability;
@@ -73,7 +73,7 @@ enum PointerKind<'tcx> {
     /// No metadata attached, ie pointer to sized type or foreign type
     Thin,
     /// A trait object
-    VTable(Option<ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>>),
+    VTable(&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>),
     /// Slice
     Length,
     /// The unsize info of this projection or opaque type
@@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         Ok(match *t.kind() {
             ty::Slice(_) | ty::Str => Some(PointerKind::Length),
-            ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal())),
+            ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),
             ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
                 None => Some(PointerKind::Thin),
                 Some(f) => {
@@ -759,7 +759,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 Err(CastError::IllegalCast)
             }
 
-            // ptr -> *
+            // ptr -> ptr
             (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
 
             // ptr-addr-cast
@@ -803,40 +803,82 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     fn check_ptr_ptr_cast(
         &self,
         fcx: &FnCtxt<'a, 'tcx>,
-        m_expr: ty::TypeAndMut<'tcx>,
-        m_cast: ty::TypeAndMut<'tcx>,
+        m_src: ty::TypeAndMut<'tcx>,
+        m_dst: ty::TypeAndMut<'tcx>,
     ) -> Result<CastKind, CastError> {
-        debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
+        debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_src, m_dst);
         // ptr-ptr cast. vtables must match.
 
-        let expr_kind = fcx.pointer_kind(m_expr.ty, self.span)?;
-        let cast_kind = fcx.pointer_kind(m_cast.ty, self.span)?;
+        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)?);
 
-        let Some(cast_kind) = cast_kind else {
+        match (src_kind, dst_kind) {
             // We can't cast if target pointer kind is unknown
-            return Err(CastError::UnknownCastPtrKind);
-        };
-
-        // Cast to thin pointer is OK
-        if cast_kind == PointerKind::Thin {
-            return Ok(CastKind::PtrPtrCast);
-        }
+            (_, None) => Err(CastError::UnknownCastPtrKind),
+            // Cast to thin pointer is OK
+            (_, Some(PointerKind::Thin)) => Ok(CastKind::PtrPtrCast),
 
-        let Some(expr_kind) = expr_kind else {
             // We can't cast to fat pointer if source pointer kind is unknown
-            return Err(CastError::UnknownExprPtrKind);
-        };
+            (None, _) => Err(CastError::UnknownExprPtrKind),
+
+            // thin -> fat? report invalid cast (don't complain about vtable kinds)
+            (Some(PointerKind::Thin), _) => Err(CastError::SizedUnsizedCast),
+
+            // trait object -> trait object? need to do additional checks
+            (Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => {
+                match (src_tty.principal(), dst_tty.principal()) {
+                    // A<dyn Trait + Auto> -> B<dyn Trait' + Auto'>. need to make sure
+                    // - traits are the same & have the same generic arguments
+                    // - Auto' is a subset of Auto
+                    //
+                    // This is checked by checking `dyn Trait + Auto + 'erased: Unsize<dyn Trait' + Auto' + 'erased>`.
+                    (Some(_), Some(_)) => {
+                        let tcx = fcx.tcx;
+
+                        // We need to reconstruct trait object types.
+                        // `m_src` and `m_dst` won't work for us here because they will potentially
+                        // contain wrappers, which we do not care about.
+                        //
+                        // e.g. we want to allow `dyn T -> (dyn T,)`, etc.
+                        let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(src_tty, tcx.lifetimes.re_erased, ty::Dyn));
+                        let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(dst_tty, tcx.lifetimes.re_erased, ty::Dyn));
+
+                        // `dyn Src: Unsize<dyn Dst>`
+                        let cause = fcx.misc(self.span);
+                        let obligation = Obligation::new(
+                            tcx,
+                            cause,
+                            fcx.param_env,
+                            ty::TraitRef::new(
+                                tcx,
+                                tcx.require_lang_item(LangItem::Unsize, Some(self.span)),
+                                [src_obj, dst_obj],
+                            )
+                        );
 
-        // thin -> fat? report invalid cast (don't complain about vtable kinds)
-        if expr_kind == PointerKind::Thin {
-            return Err(CastError::SizedUnsizedCast);
-        }
+                        fcx.register_predicate(obligation);
 
-        // vtable kinds must match
-        if fcx.tcx.erase_regions(cast_kind) == fcx.tcx.erase_regions(expr_kind) {
-            Ok(CastKind::PtrPtrCast)
-        } else {
-            Err(CastError::DifferingKinds)
+                        // FIXME: ideally we'd maybe add a flag here, so that borrowck knows that
+                        //        it needs to borrowck this ptr cast. this is made annoying by the
+                        //        fact that `thir` does not have `CastKind` and mir restores it
+                        //        from types.
+                        Ok(CastKind::PtrPtrCast)
+                    }
+
+                    // dyn Auto -> dyn Auto'? ok.
+                    (None, None)
+                    // dyn Trait -> dyn Auto? ok.
+                    | (Some(_), None)=> Ok(CastKind::PtrPtrCast),
+
+                    // dyn Auto -> dyn Trait? not ok.
+                    (None, Some(_)) => Err(CastError::DifferingKinds),
+                }
+            }
+
+            // fat -> fat? metadata kinds must match
+            (Some(src_kind), Some(dst_kind)) if src_kind == dst_kind => Ok(CastKind::PtrPtrCast),
+
+            (_, _) => Err(CastError::DifferingKinds),
         }
     }
 
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 1ec095a46f7..65bcb241e4a 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -2374,7 +2374,7 @@ impl dyn Error + Send {
         let err: Box<dyn Error> = self;
         <dyn Error>::downcast(err).map_err(|s| unsafe {
             // Reapply the `Send` marker.
-            Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send))
+            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
         })
     }
 }
@@ -2387,8 +2387,8 @@ impl dyn Error + Send + Sync {
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
         let err: Box<dyn Error> = self;
         <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // Reapply the `Send + Sync` marker.
-            Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send + Sync))
+            // Reapply the `Send + Sync` markers.
+            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
         })
     }
 }
diff --git a/tests/ui/cast/ptr-to-trait-obj-add-auto.rs b/tests/ui/cast/ptr-to-trait-obj-add-auto.rs
index b719cfed600..4758132b65d 100644
--- a/tests/ui/cast/ptr-to-trait-obj-add-auto.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-add-auto.rs
@@ -1,9 +1,9 @@
-// check-pass
+// check-fail
 
 trait Trait<'a> {}
 
 fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) {
-    x as _
+    x as _ //~ error: the trait bound `dyn Trait<'_>: Unsize<dyn Trait<'_> + Send>` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-add-auto.stderr b/tests/ui/cast/ptr-to-trait-obj-add-auto.stderr
new file mode 100644
index 00000000000..0c35db57b30
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-add-auto.stderr
@@ -0,0 +1,11 @@
+error[E0277]: the trait bound `dyn Trait<'_>: Unsize<dyn Trait<'_> + Send>` is not satisfied
+  --> $DIR/ptr-to-trait-obj-add-auto.rs:6:5
+   |
+LL |     x as _
+   |     ^^^^^^ the trait `Unsize<dyn Trait<'_> + Send>` is not implemented for `dyn Trait<'_>`
+   |
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
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 c1418a93088..1859dd8dac0 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-args.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-different-args.rs
@@ -16,17 +16,17 @@ impl<T> Trait<Y> for T {}
 
 fn main() {
     let a: *const dyn A = &();
-    let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
+    let b: *const dyn B = a as _; //~ error: the trait bound `dyn A: Unsize<dyn B>` is not satisfied
 
     let x: *const dyn Trait<X> = &();
-    let y: *const dyn Trait<Y> = x as _; //~ error: casting `*const dyn Trait<X>` as `*const dyn Trait<Y>` is invalid
+    let y: *const dyn Trait<Y> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied
 
     _ = (b, y);
 }
 
 fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
-    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
+    let _: *const dyn Trait<T> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<T>>` is not satisfied
+    let _: *const dyn Trait<X> = t as _; //~ error: the trait bound `dyn Trait<T>: Unsize<dyn Trait<X>>` is not satisfied
 }
 
 trait Assocked {
@@ -34,5 +34,5 @@ trait Assocked {
 }
 
 fn change_assoc(x: *mut dyn Assocked<Assoc = u8>) -> *mut dyn Assocked<Assoc = u32> {
-    x as _
+    x as _ //~ error: the trait bound `dyn Assocked<Assoc = u8>: Unsize<dyn Assocked<Assoc = u32>>` is not satisfied
 }
\ No newline at end of file
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 cd67b52ad27..e2cd9c8fa90 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
@@ -1,35 +1,51 @@
-error[E0606]: casting `*const dyn A` as `*const dyn B` is invalid
+error[E0277]: the trait bound `dyn A: Unsize<dyn B>` is not satisfied
   --> $DIR/ptr-to-trait-obj-different-args.rs:19:27
    |
 LL |     let b: *const dyn B = a as _;
-   |                           ^^^^^^
+   |                           ^^^^^^ the trait `Unsize<dyn B>` is not implemented for `dyn A`
    |
-   = note: vtable kinds may not match
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
 
-error[E0606]: casting `*const dyn Trait<X>` as `*const dyn Trait<Y>` is invalid
+error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied
   --> $DIR/ptr-to-trait-obj-different-args.rs:22:34
    |
 LL |     let y: *const dyn Trait<Y> = x as _;
-   |                                  ^^^^^^
+   |                                  ^^^^^^ the trait `Unsize<dyn Trait<Y>>` is not implemented for `dyn Trait<X>`
    |
-   = note: vtable kinds may not match
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
 
-error[E0606]: casting `*const (dyn Trait<X> + 'static)` as `*const dyn Trait<T>` is invalid
+error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<T>>` is not satisfied
   --> $DIR/ptr-to-trait-obj-different-args.rs:28:34
    |
 LL |     let _: *const dyn Trait<T> = x as _;
-   |                                  ^^^^^^
+   |                                  ^^^^^^ the trait `Unsize<dyn Trait<T>>` is not implemented for `dyn Trait<X>`
    |
-   = note: vtable kinds may not match
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) where dyn Trait<X>: Unsize<dyn Trait<T>> {
+   |                                                               ++++++++++++++++++++++++++++++++++++++++
 
-error[E0606]: casting `*const (dyn Trait<T> + 'static)` as `*const dyn Trait<X>` is invalid
+error[E0277]: the trait bound `dyn Trait<T>: Unsize<dyn Trait<X>>` is not satisfied
   --> $DIR/ptr-to-trait-obj-different-args.rs:29:34
    |
 LL |     let _: *const dyn Trait<X> = t as _;
-   |                                  ^^^^^^
+   |                                  ^^^^^^ the trait `Unsize<dyn Trait<X>>` is not implemented for `dyn Trait<T>`
+   |
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) where dyn Trait<T>: Unsize<dyn Trait<X>> {
+   |                                                               ++++++++++++++++++++++++++++++++++++++++
+
+error[E0277]: the trait bound `dyn Assocked<Assoc = u8>: Unsize<dyn Assocked<Assoc = u32>>` is not satisfied
+  --> $DIR/ptr-to-trait-obj-different-args.rs:37:5
+   |
+LL |     x as _
+   |     ^^^^^^ the trait `Unsize<dyn Assocked<Assoc = u32>>` is not implemented for `dyn Assocked<Assoc = u8>`
    |
-   = note: vtable kinds may not match
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0606`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
index bafa5c95840..d994723981f 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
@@ -1,4 +1,4 @@
-// check-pass
+// check-fail
 //
 // issue: <https://github.com/rust-lang/rust/issues/120217>
 
@@ -9,7 +9,7 @@ trait Static<'a> {
 }
 
 fn bad_cast<'a>(x: *const dyn Static<'static>) -> *const dyn Static<'a> {
-    x as _
+    x as _ //~ error: lifetime may not live long enough
 }
 
 impl Static<'static> for () {
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr
new file mode 100644
index 00000000000..b7319e3356b
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-lt-ext.rs:12:5
+   |
+LL | fn bad_cast<'a>(x: *const dyn Static<'static>) -> *const dyn Static<'a> {
+   |             -- lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 1 previous error
+
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 136673b6053..ea17fcd0da5 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
@@ -1,17 +1,18 @@
-// check-pass
+// check-fail
 
 trait Trait<'a> {}
 
 fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
-    x as _
+    x as _ //~ error: lifetime may not live long enough
+           //~| error: lifetime may not live long enough
 }
 
 fn change_lt_ab<'a: 'b, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
-    x as _
+    x as _ //~ error: lifetime may not live long enough
 }
 
 fn change_lt_ba<'a, 'b: 'a>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
-    x as _
+    x as _ //~ error: lifetime may not live long enough
 }
 
 trait Assocked {
@@ -21,13 +22,15 @@ trait Assocked {
 fn change_assoc_0<'a, 'b>(
     x: *mut dyn Assocked<Assoc = dyn Send + 'a>,
 ) -> *mut dyn Assocked<Assoc = dyn Send + 'b> {
-    x as _
+    x as _ //~ error: lifetime may not live long enough
+           //~| error: lifetime may not live long enough
 }
 
 fn change_assoc_1<'a, 'b>(
     x: *mut dyn Assocked<Assoc = dyn Trait<'a>>,
 ) -> *mut dyn Assocked<Assoc = dyn Trait<'b>> {
-    x as _
+    x as _ //~ error: lifetime may not live long enough
+           //~| error: lifetime may not live long enough
 }
 
 
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
new file mode 100644
index 00000000000..7044e4dec1f
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
@@ -0,0 +1,136 @@
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:6:5
+   |
+LL | fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+   |              --  -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:6:5
+   |
+LL | fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+   |              --  -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'b` and `'a` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:11:5
+   |
+LL | fn change_lt_ab<'a: 'b, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+   |                 --      -- lifetime `'b` defined here
+   |                 |
+   |                 lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:15:5
+   |
+LL | fn change_lt_ba<'a, 'b: 'a>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+   |                 --  -- lifetime `'b` defined here
+   |                 |
+   |                 lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5
+   |
+LL | fn change_assoc_0<'a, 'b>(
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Send>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5
+   |
+LL | fn change_assoc_0<'a, 'b>(
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Send>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'b` and `'a` must be the same: replace one with the other
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5
+   |
+LL | fn change_assoc_1<'a, 'b>(
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Trait<'_>>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5
+   |
+LL | fn change_assoc_1<'a, 'b>(
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Trait<'_>>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+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
+
diff --git a/tests/ui/mismatched_types/cast-rfc0401.rs b/tests/ui/mismatched_types/cast-rfc0401.rs
index 57222f45947..05e39f86cdf 100644
--- a/tests/ui/mismatched_types/cast-rfc0401.rs
+++ b/tests/ui/mismatched_types/cast-rfc0401.rs
@@ -66,7 +66,7 @@ fn main()
 
     let cf: *const dyn Foo = &0;
     let _ = cf as *const [u16]; //~ ERROR is invalid
-    let _ = cf as *const dyn Bar; //~ ERROR is invalid
+    let _ = cf as *const dyn Bar; //~ ERROR the trait bound `dyn Foo: Unsize<dyn Bar>` is not satisfied
 
     vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>(); //~ ERROR is invalid
 }
diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr
index 142a52aef13..9f4a7aa858e 100644
--- a/tests/ui/mismatched_types/cast-rfc0401.stderr
+++ b/tests/ui/mismatched_types/cast-rfc0401.stderr
@@ -210,13 +210,13 @@ LL |     let _ = cf as *const [u16];
    |
    = note: vtable kinds may not match
 
-error[E0606]: casting `*const dyn Foo` as `*const dyn Bar` is invalid
+error[E0277]: the trait bound `dyn Foo: Unsize<dyn Bar>` is not satisfied
   --> $DIR/cast-rfc0401.rs:69:13
    |
 LL |     let _ = cf as *const dyn Bar;
-   |             ^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<dyn Bar>` is not implemented for `dyn Foo`
    |
-   = note: vtable kinds may not match
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
   --> $DIR/cast-rfc0401.rs:53:13