about summary refs log tree commit diff
path: root/compiler
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
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')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs2
-rw-r--r--compiler/rustc_transmute/src/lib.rs2
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs43
4 files changed, 33 insertions, 18 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 71419fe0eee..8224fdf591a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2751,7 +2751,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else {
                 span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
             };
-        // FIXME(bryangarza): Need to flatten here too
+        // FIXME(bryangarza): Is this enough, or should we resolve all nested
+        // obligations like we do for `confirm_transmutability_candidate(...)?`
         match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
             obligation.cause,
             src_and_dst,
@@ -2780,7 +2781,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     rustc_transmute::Reason::DstIsPrivate => format!(
                         "`{dst}` is or contains a type or field that is not visible in that scope"
                     ),
-                    // FIXME(bryangarza): Include the number of bytes of src and dst
                     rustc_transmute::Reason::DstIsTooBig => {
                         format!("The size of `{src}` is smaller than the size of `{dst}`")
                     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 528a5f9dc61..e3d982b5c3f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -329,7 +329,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         )
                     };
 
-                    // // FIXME(bryangarza): Check src.mutability or dst.mutability to know whether dst -> src obligation is needed
+                    // FIXME(bryangarza): Check src.mutability or dst.mutability to know whether dst -> src obligation is needed
                     Ok(vec![make_obl(src.ty, dst.ty), make_obl(dst.ty, src.ty)])
                 }
             }
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);