about summary refs log tree commit diff
path: root/compiler/rustc_transmute
diff options
context:
space:
mode:
authorBryan Garza <1396101+bryangarza@users.noreply.github.com>2023-04-27 17:19:16 -0700
committerBryan Garza <1396101+bryangarza@users.noreply.github.com>2023-05-24 14:52:19 -0700
commit94ad084ac611b7c21d4f08b1eb30623f09db2cd0 (patch)
tree10214d71cf1548ea8426c626b514c41908ccc256 /compiler/rustc_transmute
parent263a4f2cb6b455f9c4ae46493d59369c378a85ea (diff)
downloadrust-94ad084ac611b7c21d4f08b1eb30623f09db2cd0.tar.gz
rust-94ad084ac611b7c21d4f08b1eb30623f09db2cd0.zip
Safe Transmute: Fix propagation of errors
- Make sure that the most specific Reason is the one that bubbles up when we
  are folding over the `Answer` tree. `Reason::DstIsBitIncompatible` is the
  least specific, so that should be used only when there isn't anything else
  available.
- Small fixes where we used the wrong Reason variant.
- Tiny cleanups
Diffstat (limited to 'compiler/rustc_transmute')
-rw-r--r--compiler/rustc_transmute/src/lib.rs2
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs43
2 files changed, 30 insertions, 15 deletions
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index baf63e6d3a2..60adbc1b470 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)]
+#![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type, let_chains)]
 #![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 de00efb1614..47f61a80840 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -78,11 +78,12 @@ mod rustc {
                 match (src, dst) {
                     // Answer `Ok(None)` here, because 'unknown layout' and type errors will already
                     // be reported by rustc. No need to spam the user with more errors.
-                    (Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => Err(Ok(None)),
-                    (Err(Err::Unknown), _) | (_, Err(Err::Unknown)) => Err(Ok(None)),
-                    (Err(Err::Unspecified), _) | (_, Err(Err::Unspecified)) => {
-                        Err(Err(Reason::SrcIsUnspecified))
-                    }
+                    (Err(Err::TypeError(_)), _)
+                    | (_, Err(Err::TypeError(_)))
+                    | (Err(Err::Unknown), _)
+                    | (_, Err(Err::Unknown)) => Err(Ok(None)),
+                    (Err(Err::Unspecified), _) => Err(Err(Reason::SrcIsUnspecified)),
+                    (_, Err(Err::Unspecified)) => Err(Err(Reason::DstIsUnspecified)),
                     (Ok(src), Ok(dst)) => Ok((src, dst)),
                 }
             });
@@ -316,12 +317,19 @@ where
     }
 }
 
-fn and<R>(lhs: Answer<R>, rhs: Answer<R>) -> Answer<R> {
-    // Should propagate errors on the right side, because the initial value
-    // used in `apply` is on the left side.
-    let rhs = rhs?;
-    let lhs = lhs?;
-    Ok(match (lhs, rhs) {
+fn and<R>(lhs: Answer<R>, rhs: Answer<R>) -> Answer<R>
+where
+    R: PartialEq,
+{
+    // If both are errors, then we should return the more specific one
+    if lhs.is_err() && rhs.is_err() {
+        if lhs == Err(Reason::DstIsBitIncompatible) {
+            return rhs;
+        } else {
+            return lhs;
+        }
+    }
+    Ok(match (lhs?, rhs?) {
         // If only one side has a condition, pass it along
         (None, other) | (other, None) => other,
         // If both sides have IfAll conditions, merge them
@@ -340,10 +348,17 @@ fn and<R>(lhs: Answer<R>, rhs: Answer<R>) -> Answer<R> {
     })
 }
 
-fn or<R>(lhs: Answer<R>, rhs: Answer<R>) -> Answer<R> {
-    // If both are errors, then we should return the one on the right
+fn or<R>(lhs: Answer<R>, rhs: Answer<R>) -> Answer<R>
+where
+    R: PartialEq,
+{
+    // If both are errors, then we should return the more specific one
     if lhs.is_err() && rhs.is_err() {
-        return rhs;
+        if lhs == Err(Reason::DstIsBitIncompatible) {
+            return rhs;
+        } else {
+            return lhs;
+        }
     }
     // Otherwise, errors can be ignored for the rest of the pattern matching
     let lhs = lhs.unwrap_or(None);