about summary refs log tree commit diff
path: root/compiler/rustc_transmute
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_transmute')
-rw-r--r--compiler/rustc_transmute/src/layout/mod.rs15
-rw-r--r--compiler/rustc_transmute/src/lib.rs2
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs22
3 files changed, 32 insertions, 7 deletions
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
index b318447e581..76d97e0e6e7 100644
--- a/compiler/rustc_transmute/src/layout/mod.rs
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -31,18 +31,21 @@ impl fmt::Debug for Byte {
 
 pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {}
 pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {
+    fn min_align(&self) -> usize;
+
+    fn is_mutable(&self) -> bool;
+}
+
+impl Def for ! {}
+impl Ref for ! {
     fn min_align(&self) -> usize {
-        1
+        unreachable!()
     }
-
     fn is_mutable(&self) -> bool {
-        false
+        unreachable!()
     }
 }
 
-impl Def for ! {}
-impl Ref for ! {}
-
 #[cfg(feature = "rustc")]
 pub mod rustc {
     use rustc_middle::mir::Mutability;
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index 60adbc1b470..baf63e6d3a2 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type, let_chains)]
+#![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type)]
 #![allow(dead_code, unused_variables)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index 47f61a80840..0f4a096cdae 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -203,8 +203,29 @@ where
         if let Some(answer) = cache.get(&(src_state, dst_state)) {
             answer.clone()
         } else {
+            debug!(?src_state, ?dst_state);
+            debug!(src = ?self.src);
+            debug!(dst = ?self.dst);
+            debug!(
+                src_transitions_len = self.src.transitions.len(),
+                dst_transitions_len = self.dst.transitions.len()
+            );
             let answer = if dst_state == self.dst.accepting {
                 // truncation: `size_of(Src) >= size_of(Dst)`
+                //
+                // Why is truncation OK to do? Because even though the Src is bigger, all we care about
+                // is whether we have enough data for the Dst to be valid in accordance with what its
+                // type dictates.
+                // For example, in a u8 to `()` transmutation, we have enough data available from the u8
+                // to transmute it to a `()` (though in this case does `()` really need any data to
+                // begin with? It doesn't). Same thing with u8 to fieldless struct.
+                // Now then, why is something like u8 to bool not allowed? That is not because the bool
+                // is smaller in size, but rather because those 2 bits that we are re-interpreting from
+                // the u8 could introduce invalid states for the bool type.
+                //
+                // So, if it's possible to transmute to a smaller Dst by truncating, and we can guarantee
+                // that none of the actually-used data can introduce an invalid state for Dst's type, we
+                // are able to safely transmute, even with truncation.
                 Ok(None)
             } else if src_state == self.src.accepting {
                 // extension: `size_of(Src) >= size_of(Dst)`
@@ -259,6 +280,7 @@ where
                 // ...if `refs_answer` was computed lazily. The below early
                 // returns can be deleted without impacting the correctness of
                 // the algoritm; only its performance.
+                debug!(?bytes_answer);
                 match bytes_answer {
                     Err(_) if !self.assume.validity => return bytes_answer,
                     Ok(None) if self.assume.validity => return bytes_answer,