Add more checks for pointers with vtable meta

The rules for casting `*mut X<dyn A>` -> `*mut Y<dyn B>` are as follows:
- If `B` has a principal
  - `A` must have exactly the same principal (including generics)
  - Auto traits of `B` must be a subset of autotraits in `A`

Note that `X<_>` and `Y<_>` can be identity, or arbitrary structs with last field being the dyn type.
The lifetime of the trait object itself (`dyn ... + 'a`) is not checked.

This prevents a few soundness issues with `#![feature(arbitrary_self_types)]` and trait upcasting.
Namely, these checks make sure that vtable is always valid for the pointee.
This commit is contained in:
Maybe Waffle 2024-02-12 21:24:48 +00:00 committed by Maybe Lapkin
parent 9e8ef92da0
commit 5645e8e285
13 changed files with 331 additions and 67 deletions

View File

@ -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))
}

View File

@ -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);
};
(_, None) => Err(CastError::UnknownCastPtrKind),
// Cast to thin pointer is OK
if cast_kind == PointerKind::Thin {
return Ok(CastKind::PtrPtrCast);
}
(_, 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)
if expr_kind == PointerKind::Thin {
return Err(CastError::SizedUnsizedCast);
(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],
)
);
fcx.register_predicate(obligation);
// 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)
}
// vtable kinds must match
if fcx.tcx.erase_regions(cast_kind) == fcx.tcx.erase_regions(expr_kind) {
Ok(CastKind::PtrPtrCast)
} else {
Err(CastError::DifferingKinds)
// 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),
}
}

View File

@ -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)
})
}
}

View File

@ -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() {}

View File

@ -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`.

View File

@ -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
}

View File

@ -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: 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<T>: Unsize<dyn Trait<X>> {
| ++++++++++++++++++++++++++++++++++++++++
error: aborting due to 4 previous errors
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: 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
For more information about this error, try `rustc --explain E0606`.
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -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 () {

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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