about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-10-08 14:38:18 +0200
committerGitHub <noreply@github.com>2022-10-08 14:38:18 +0200
commit6bcdf8aa7435a3c72a7ea3f5e54b67f5faec9264 (patch)
treed515261fb8e1e3860c945e506182d0f4b4e943cb
parenta688a0305fad9219505a8f2576446510601bafe8 (diff)
parentd90d055691267447f319b0f240bfe60cacb1d266 (diff)
Rollup merge of #101520 - oli-obk:transmute_lifetimes, r=compiler-errors
Allow transmutes between the same types after erasing lifetimes

r? ````@compiler-errors````  on the impl

fixes #101081

See discussion in the issue and at https://rust-lang.zulipchat.com/#narrow/stream/326866-t-types.2Fnominated/topic/.23101081.3A.20Regression.20transmuting.20.60RwLockReadGuard.3CT.3A.20.3FSized.3E.E2.80.A6

I think this may need lang team signoff as its implications may go beyond the jurisdiction of T-types

I'll write up a proper summary later
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs20
-rw-r--r--src/test/ui/transmute-equal-assoc-types.rs4
-rw-r--r--src/test/ui/transmute-equal-assoc-types.stderr11
-rw-r--r--src/test/ui/transmute/lifetimes.rs23
-rw-r--r--src/test/ui/transmute/main.rs2
-rw-r--r--src/test/ui/transmute/main.stderr10
6 files changed, 43 insertions, 27 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 4abc00cefb6..25228f424cd 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 6f357543e5c..d1b593b7f0a 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<F: Foo>(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 ce7657f9640..00000000000
--- 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: `<F as Foo>::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 00000000000..94319155139
--- /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<T>);
+
+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 cb46fc5ec46..da4a0a660c8 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: <C as TypeConstructor<'a>>::T)
                                         -> <C as TypeConstructor<'b>>::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 d519f03682b..6cb0d7f67e0 100644
--- a/src/test/ui/transmute/main.stderr
+++ b/src/test/ui/transmute/main.stderr
@@ -1,12 +1,4 @@
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/main.rs:13:5
-   |
-LL |     transmute(x)
-   |     ^^^^^^^^^
-   |
-   = note: `<C as TypeConstructor<'_>>::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
    |
 LL |     let x: u8 = transmute(10u16);
@@ -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`.