diff options
| author | Maybe Lapkin <waffle.lapkin@gmail.com> | 2024-07-04 17:53:37 +0200 |
|---|---|---|
| committer | Maybe Lapkin <waffle.lapkin@gmail.com> | 2024-07-04 17:57:31 +0200 |
| commit | a1f20f17c86a7a0a51728be48afd121d5ae2df64 (patch) | |
| tree | 086b8f93b8c0d9413d763a503c41ed8ef28be6ac | |
| parent | 9ef533e8de83aba38a460eae4eec41859f188bf1 (diff) | |
| download | rust-a1f20f17c86a7a0a51728be48afd121d5ae2df64.tar.gz rust-a1f20f17c86a7a0a51728be48afd121d5ae2df64.zip | |
Properly normalize types in bck when checking pointer casts
3 files changed, 47 insertions, 2 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 81ce7418852..6fd49c8027b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2320,8 +2320,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { (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); + let mut normalize = |t| self.normalize(t, location); + let src_tail = + tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ()); + let dst_tail = + tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ()); // This checks (lifetime part of) vtable validity for pointer casts, // which is irrelevant when there are aren't principal traits on both sides (aka only auto traits). diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs new file mode 100644 index 00000000000..cdd55e24392 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs @@ -0,0 +1,27 @@ +//@ check-fail +// +// Make sure we can't trick the compiler by using a projection. + +trait Cat<'a> {} +impl Cat<'_> for () {} + +trait Id { + type Id: ?Sized; +} +impl<T: ?Sized> Id for T { + type Id = T; +} + +struct S<T: ?Sized> { + tail: <T as Id>::Id, +} + +fn m<'a>() { + let unsend: *const dyn Cat<'a> = &(); + let _send = unsend as *const S<dyn Cat<'static>>; + //~^ error: lifetime may not live long enough +} + +fn main() { + m(); +} diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr new file mode 100644 index 00000000000..d1d598e603f --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:21:17 + | +LL | fn m<'a>() { + | -- lifetime `'a` defined here +LL | let unsend: *const dyn Cat<'a> = &(); +LL | let _send = unsend as *const S<dyn Cat<'static>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type `S<dyn Cat<'_>>`, which makes the generic argument `dyn Cat<'_>` invariant + = note: the struct `S<T>` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to 1 previous error + |
