From d90d055691267447f319b0f240bfe60cacb1d266 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 7 Sep 2022 07:51:11 +0000 Subject: [PATCH] Allow transmutes between the same types after erasing lifetimes --- .../src/check/intrinsicck.rs | 20 ++++++++++++---- src/test/ui/transmute-equal-assoc-types.rs | 4 +++- .../ui/transmute-equal-assoc-types.stderr | 11 --------- src/test/ui/transmute/lifetimes.rs | 23 +++++++++++++++++++ src/test/ui/transmute/main.rs | 2 +- src/test/ui/transmute/main.stderr | 10 +------- 6 files changed, 43 insertions(+), 27 deletions(-) delete mode 100644 src/test/ui/transmute-equal-assoc-types.stderr create mode 100644 src/test/ui/transmute/lifetimes.rs diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 4abc00cefb68f..25228f424cd07 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -44,13 +44,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) { let tcx = self.tcx; let span = tcx.hir().span(hir_id); - let convert = |ty: Ty<'tcx>| { + let normalize = |ty| { let ty = self.resolve_vars_if_possible(ty); - let ty = tcx.normalize_erasing_regions(self.param_env, ty); - (SizeSkeleton::compute(ty, tcx, self.param_env), ty) + self.tcx.normalize_erasing_regions(self.param_env, ty) }; - let (sk_from, from) = convert(from); - let (sk_to, to) = convert(to); + let from = normalize(from); + let to = normalize(to); + trace!(?from, ?to); + + // Transmutes that are only changing lifetimes are always ok. + if from == to { + return; + } + + let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env); + let sk_from = skel(from); + let sk_to = skel(to); + trace!(?sk_from, ?sk_to); // Check for same size using the skeletons. if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) { diff --git a/src/test/ui/transmute-equal-assoc-types.rs b/src/test/ui/transmute-equal-assoc-types.rs index 6f357543e5c44..d1b593b7f0a71 100644 --- a/src/test/ui/transmute-equal-assoc-types.rs +++ b/src/test/ui/transmute-equal-assoc-types.rs @@ -1,9 +1,11 @@ +// check-pass + trait Foo { type Bar; } unsafe fn noop(foo: F::Bar) -> F::Bar { - ::std::mem::transmute(foo) //~ ERROR cannot transmute between types of different sizes + ::std::mem::transmute(foo) } fn main() {} diff --git a/src/test/ui/transmute-equal-assoc-types.stderr b/src/test/ui/transmute-equal-assoc-types.stderr deleted file mode 100644 index ce7657f9640b4..0000000000000 --- a/src/test/ui/transmute-equal-assoc-types.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-equal-assoc-types.rs:6:5 - | -LL | ::std::mem::transmute(foo) - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: `::Bar` does not have a fixed size - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0512`. diff --git a/src/test/ui/transmute/lifetimes.rs b/src/test/ui/transmute/lifetimes.rs new file mode 100644 index 0000000000000..943191551396d --- /dev/null +++ b/src/test/ui/transmute/lifetimes.rs @@ -0,0 +1,23 @@ +// check-pass + +use std::ptr::NonNull; + +struct Foo<'a, T: ?Sized>(&'a (), NonNull); + +fn foo<'a, 'b, T: ?Sized>(x: Foo<'a, T>) -> Foo<'b, T> { + unsafe { std::mem::transmute(x) } +} + +struct Bar<'a, T: ?Sized>(&'a T); + +fn bar<'a, 'b, T: ?Sized>(x: Bar<'a, T>) -> Bar<'b, T> { + unsafe { std::mem::transmute(x) } +} + +struct Boo<'a, T: ?Sized>(&'a T, u32); + +fn boo<'a, 'b, T: ?Sized>(x: Boo<'a, T>) -> Boo<'b, T> { + unsafe { std::mem::transmute(x) } +} + +fn main() {} diff --git a/src/test/ui/transmute/main.rs b/src/test/ui/transmute/main.rs index cb46fc5ec467d..da4a0a660c8cb 100644 --- a/src/test/ui/transmute/main.rs +++ b/src/test/ui/transmute/main.rs @@ -10,7 +10,7 @@ pub trait TypeConstructor<'a> { unsafe fn transmute_lifetime<'a, 'b, C>(x: >::T) -> >::T where for<'z> C: TypeConstructor<'z> { - transmute(x) //~ ERROR cannot transmute between types of different sizes + transmute(x) } unsafe fn sizes() { diff --git a/src/test/ui/transmute/main.stderr b/src/test/ui/transmute/main.stderr index d519f03682b5d..6cb0d7f67e085 100644 --- a/src/test/ui/transmute/main.stderr +++ b/src/test/ui/transmute/main.stderr @@ -1,11 +1,3 @@ -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:13:5 - | -LL | transmute(x) - | ^^^^^^^^^ - | - = note: `>::T` does not have a fixed size - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/main.rs:17:17 | @@ -33,6 +25,6 @@ LL | let x: Foo = transmute(10); = note: source type: `i32` (32 bits) = note: target type: `Foo` (0 bits) -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0512`.