about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille Gillot <gillot.camille@gmail.com>2025-08-14 22:54:50 +0000
committerCamille Gillot <gillot.camille@gmail.com>2025-08-22 20:10:27 +0000
commita3c878f813dd9c7c788cbe8d817699f2ef927e4e (patch)
treee13ccd420f7249b14f5333bbf2d941db1ff40915
parentd20509c2a0c71b60aa2b51566e4d14920e8a1661 (diff)
downloadrust-a3c878f813dd9c7c788cbe8d817699f2ef927e4e.tar.gz
rust-a3c878f813dd9c7c788cbe8d817699f2ef927e4e.zip
Separate transmute checking from typeck.
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs207
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs13
-rw-r--r--compiler/rustc_interface/src/passes.rs3
-rw-r--r--compiler/rustc_middle/src/query/mod.rs5
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs6
-rw-r--r--tests/ui/const-generics/transmute-fail.stderr16
-rw-r--r--tests/ui/consts/transmute-size-mismatch-before-typeck.rs7
-rw-r--r--tests/ui/consts/transmute-size-mismatch-before-typeck.stderr13
-rw-r--r--tests/ui/impl-trait/transmute/in-defining-scope.rs9
-rw-r--r--tests/ui/impl-trait/transmute/in-defining-scope.stderr56
-rw-r--r--tests/ui/layout/base-layout-is-sized-ice-123078.rs4
-rw-r--r--tests/ui/layout/base-layout-is-sized-ice-123078.stderr12
-rw-r--r--tests/ui/layout/normalization-failure.rs4
-rw-r--r--tests/ui/layout/normalization-failure.stderr2
-rw-r--r--tests/ui/layout/transmute-to-tail-with-err.rs1
-rw-r--r--tests/ui/layout/transmute-to-tail-with-err.stderr14
-rw-r--r--tests/ui/type-alias-impl-trait/issue-53092-2.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-53092-2.stderr64
-rw-r--r--tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs1
-rw-r--r--tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr12
-rw-r--r--tests/ui/type/pattern_types/or_patterns_invalid.rs4
-rw-r--r--tests/ui/type/pattern_types/or_patterns_invalid.stderr39
24 files changed, 253 insertions, 254 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index b80a2af3100..5aec50c8b53 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -83,14 +83,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks;
     }
 
-    pub(in super::super) fn check_transmutes(&self) {
-        let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut();
-        debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len());
-        for (from, to, hir_id) in deferred_transmute_checks.drain(..) {
-            self.check_transmute(from, to, hir_id);
-        }
-    }
-
     pub(in super::super) fn check_asms(&self) {
         let mut deferred_asm_checks = self.deferred_asm_checks.borrow_mut();
         debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 194e420b606..fffff7e6f8c 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -8,10 +8,9 @@ use rustc_index::Idx;
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::def_id::LocalDefId;
 use tracing::trace;
 
-use super::FnCtxt;
-
 /// If the type is `Option<T>`, it will return `T`, otherwise
 /// the type itself. Works on most `Option`-like types.
 fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
@@ -39,119 +38,115 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
     ty
 }
 
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    /// FIXME: Move this check out of typeck, since it'll easily cycle when revealing opaques,
-    /// and we shouldn't need to check anything here if the typeck results are tainted.
-    pub(crate) fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
-        let tcx = self.tcx;
-        let dl = &tcx.data_layout;
-        let span = tcx.hir_span(hir_id);
-        let normalize = |ty| {
-            let ty = self.resolve_vars_if_possible(ty);
-            if let Ok(ty) =
-                self.tcx.try_normalize_erasing_regions(self.typing_env(self.param_env), ty)
-            {
-                ty
-            } else {
-                Ty::new_error_with_message(
-                    tcx,
-                    span,
-                    "tried to normalize non-wf type in check_transmute",
-                )
-            }
-        };
-        let from = normalize(from);
-        let to = normalize(to);
-        trace!(?from, ?to);
-        if from.has_non_region_infer() || to.has_non_region_infer() {
-            // Note: this path is currently not reached in any test, so any
-            // example that triggers this would be worth minimizing and
-            // converting into a test.
-            self.dcx().span_bug(span, "argument to transmute has inference variables");
-        }
-        // Transmutes that are only changing lifetimes are always ok.
-        if from == to {
-            return;
+fn check_transmute<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
+    from: Ty<'tcx>,
+    to: Ty<'tcx>,
+    hir_id: HirId,
+) {
+    let dl = &tcx.data_layout;
+    let span = tcx.hir_span(hir_id);
+    let normalize = |ty| {
+        if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) {
+            ty
+        } else {
+            Ty::new_error_with_message(
+                tcx,
+                span,
+                format!("tried to normalize non-wf type {ty:#?} in check_transmute"),
+            )
         }
+    };
+    let from = normalize(from);
+    let to = normalize(to);
+    trace!(?from, ?to);
+    if from.has_non_region_infer() || to.has_non_region_infer() {
+        // Note: this path is currently not reached in any test, so any
+        // example that triggers this would be worth minimizing and
+        // converting into a test.
+        tcx.sess.dcx().span_bug(span, "argument to transmute has inference variables");
+    }
+    // Transmutes that are only changing lifetimes are always ok.
+    if from == to {
+        return;
+    }
 
-        let skel = |ty| SizeSkeleton::compute(ty, tcx, self.typing_env(self.param_env));
-        let sk_from = skel(from);
-        let sk_to = skel(to);
-        trace!(?sk_from, ?sk_to);
+    let skel = |ty| SizeSkeleton::compute(ty, tcx, typing_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) {
-            if sk_from.same_size(sk_to) {
-                return;
-            }
+    // Check for same size using the skeletons.
+    if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
+        if sk_from.same_size(sk_to) {
+            return;
+        }
 
-            // Special-case transmuting from `typeof(function)` and
-            // `Option<typeof(function)>` to present a clearer error.
-            let from = unpack_option_like(tcx, from);
-            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to, _)) = (from.kind(), sk_to)
-                && size_to == Pointer(dl.instruction_address_space).size(&tcx)
-            {
-                struct_span_code_err!(self.dcx(), span, E0591, "can't transmute zero-sized type")
-                    .with_note(format!("source type: {from}"))
-                    .with_note(format!("target type: {to}"))
-                    .with_help("cast with `as` to a pointer instead")
-                    .emit();
-                return;
-            }
+        // Special-case transmuting from `typeof(function)` and
+        // `Option<typeof(function)>` to present a clearer error.
+        let from = unpack_option_like(tcx, from);
+        if let (&ty::FnDef(..), SizeSkeleton::Known(size_to, _)) = (from.kind(), sk_to)
+            && size_to == Pointer(dl.instruction_address_space).size(&tcx)
+        {
+            struct_span_code_err!(tcx.sess.dcx(), span, E0591, "can't transmute zero-sized type")
+                .with_note(format!("source type: {from}"))
+                .with_note(format!("target type: {to}"))
+                .with_help("cast with `as` to a pointer instead")
+                .emit();
+            return;
         }
+    }
 
-        // Try to display a sensible error with as much information as possible.
-        let skeleton_string = |ty: Ty<'tcx>, sk: Result<_, &_>| match sk {
-            Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
-            Ok(SizeSkeleton::Known(size, _)) => {
-                if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
-                    format!("{v} bits")
-                } else {
-                    // `u128` should definitely be able to hold the size of different architectures
-                    // larger sizes should be reported as error `are too big for the target architecture`
-                    // otherwise we have a bug somewhere
-                    bug!("{:?} overflow for u128", size)
-                }
-            }
-            Ok(SizeSkeleton::Generic(size)) => {
-                if let Some(size) =
-                    self.try_structurally_resolve_const(span, size).try_to_target_usize(tcx)
-                {
-                    format!("{size} bytes")
-                } else {
-                    format!("generic size {size}")
-                }
-            }
-            Err(LayoutError::TooGeneric(bad)) => {
-                if *bad == ty {
-                    "this type does not have a fixed size".to_owned()
-                } else {
-                    format!("size can vary because of {bad}")
-                }
+    // Try to display a sensible error with as much information as possible.
+    let skeleton_string = |ty: Ty<'tcx>, sk: Result<_, &_>| match sk {
+        Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
+        Ok(SizeSkeleton::Known(size, _)) => {
+            if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
+                format!("{v} bits")
+            } else {
+                // `u128` should definitely be able to hold the size of different architectures
+                // larger sizes should be reported as error `are too big for the target architecture`
+                // otherwise we have a bug somewhere
+                bug!("{:?} overflow for u128", size)
             }
-            Err(err) => err.to_string(),
-        };
-
-        let mut err = struct_span_code_err!(
-            self.dcx(),
-            span,
-            E0512,
-            "cannot transmute between types of different sizes, \
-                                        or dependently-sized types"
-        );
-        if from == to {
-            err.note(format!("`{from}` does not have a fixed size"));
-            err.emit();
-        } else {
-            err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
-                .note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
-            if let Err(LayoutError::ReferencesError(_)) = sk_from {
-                err.delay_as_bug();
-            } else if let Err(LayoutError::ReferencesError(_)) = sk_to {
-                err.delay_as_bug();
+        }
+        Ok(SizeSkeleton::Generic(size)) => {
+            format!("generic size {size}")
+        }
+        Err(LayoutError::TooGeneric(bad)) => {
+            if *bad == ty {
+                "this type does not have a fixed size".to_owned()
             } else {
-                err.emit();
+                format!("size can vary because of {bad}")
             }
         }
+        Err(err) => err.to_string(),
+    };
+
+    let mut err = struct_span_code_err!(
+        tcx.sess.dcx(),
+        span,
+        E0512,
+        "cannot transmute between types of different sizes, or dependently-sized types"
+    );
+    if from == to {
+        err.note(format!("`{from}` does not have a fixed size"));
+        err.emit();
+    } else {
+        err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)));
+        err.note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
+        err.emit();
+    }
+}
+
+pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) {
+    assert!(!tcx.is_typeck_child(owner.to_def_id()));
+    let typeck_results = tcx.typeck(owner);
+    let None = typeck_results.tainted_by_errors else { return };
+
+    let typing_env = ty::TypingEnv::post_analysis(tcx, owner);
+    for &(from, to, hir_id) in &typeck_results.transmutes_to_check {
+        check_transmute(tcx, typing_env, from, to, hir_id);
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index aae870f7ee3..ab4181f5293 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -251,10 +251,6 @@ fn typeck_with_inspect<'tcx>(
         fcx.report_ambiguity_errors();
     }
 
-    if let None = fcx.infcx.tainted_by_errors() {
-        fcx.check_transmutes();
-    }
-
     fcx.check_asms();
 
     let typeck_results = fcx.resolve_type_vars_in_body(body);
@@ -555,6 +551,7 @@ pub fn provide(providers: &mut Providers) {
         method_autoderef_steps: method::probe::method_autoderef_steps,
         typeck,
         used_trait_imports,
+        check_transmutes: intrinsicck::check_transmutes,
         ..*providers
     };
 }
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 093de950d63..42736a07b2a 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -74,6 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         wbcx.visit_user_provided_tys();
         wbcx.visit_user_provided_sigs();
         wbcx.visit_coroutine_interior();
+        wbcx.visit_transmutes();
         wbcx.visit_offset_of_container_types();
 
         wbcx.typeck_results.rvalue_scopes =
@@ -532,6 +533,18 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         }
     }
 
+    fn visit_transmutes(&mut self) {
+        let tcx = self.tcx();
+        let fcx_typeck_results = self.fcx.typeck_results.borrow();
+        assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
+        for &(from, to, hir_id) in self.fcx.deferred_transmute_checks.borrow().iter() {
+            let span = tcx.hir_span(hir_id);
+            let from = self.resolve(from, &span);
+            let to = self.resolve(to, &span);
+            self.typeck_results.transmutes_to_check.push((from, to, hir_id));
+        }
+    }
+
     #[instrument(skip(self), level = "debug")]
     fn visit_opaque_types(&mut self) {
         let tcx = self.tcx();
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 424cba2dae8..90f7ae76387 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -1080,7 +1080,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
             if !tcx.is_typeck_child(def_id.to_def_id()) {
                 // Child unsafety and borrowck happens together with the parent
                 tcx.ensure_ok().check_unsafety(def_id);
-                tcx.ensure_ok().mir_borrowck(def_id)
+                tcx.ensure_ok().mir_borrowck(def_id);
+                tcx.ensure_ok().check_transmutes(def_id);
             }
             tcx.ensure_ok().has_ffi_unwind_calls(def_id);
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 3bb8353f49e..d4f88c458a8 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1116,6 +1116,11 @@ rustc_queries! {
     }
 
     /// Unsafety-check this `LocalDefId`.
+    query check_transmutes(key: LocalDefId) {
+        desc { |tcx| "check transmute calls inside `{}`", tcx.def_path_str(key) }
+    }
+
+    /// Unsafety-check this `LocalDefId`.
     query check_unsafety(key: LocalDefId) {
         desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
     }
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 6b187c5325a..f42dbbd2ac3 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -210,6 +210,11 @@ pub struct TypeckResults<'tcx> {
     /// on closure size.
     pub closure_size_eval: LocalDefIdMap<ClosureSizeProfileData<'tcx>>,
 
+    /// Stores the types involved in calls to `transmute` intrinsic. These are meant to be checked
+    /// outside of typeck and borrowck to avoid cycles with opaque types and coroutine layout
+    /// computation.
+    pub transmutes_to_check: Vec<(Ty<'tcx>, Ty<'tcx>, HirId)>,
+
     /// Container types and field indices of `offset_of!` expressions
     offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>,
 }
@@ -241,6 +246,7 @@ impl<'tcx> TypeckResults<'tcx> {
             rvalue_scopes: Default::default(),
             coroutine_stalled_predicates: Default::default(),
             closure_size_eval: Default::default(),
+            transmutes_to_check: Default::default(),
             offset_of_data: Default::default(),
         }
     }
diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr
index 0e26daa3a0f..953119a8c34 100644
--- a/tests/ui/const-generics/transmute-fail.stderr
+++ b/tests/ui/const-generics/transmute-fail.stderr
@@ -6,6 +6,14 @@ LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] {
    |
    = note: the length of array `[[u32; H]; W]` must be type `usize`
 
+error: the constant `W` is not of type `usize`
+  --> $DIR/transmute-fail.rs:19:9
+   |
+LL |         std::mem::transmute(v)
+   |         ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
+   |
+   = note: the length of array `[[u32; H]; W]` must be type `usize`
+
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:11:9
    |
@@ -15,14 +23,6 @@ LL |         std::mem::transmute(v)
    = note: source type: `[[u32; H + 1]; W]` (size can vary because of [u32; H + 1])
    = note: target type: `[[u32; W + 1]; H]` (size can vary because of [u32; W + 1])
 
-error: the constant `W` is not of type `usize`
-  --> $DIR/transmute-fail.rs:19:9
-   |
-LL |         std::mem::transmute(v)
-   |         ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
-   |
-   = note: the length of array `[[u32; H]; W]` must be type `usize`
-
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:26:9
    |
diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs
index ffb143da2d4..17b343d2b9b 100644
--- a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs
+++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs
@@ -1,5 +1,9 @@
+//@ normalize-stderr-64bit: "8 byte" -> "word size"
+//@ normalize-stderr-32bit: "4 byte" -> "word size"
 //@ normalize-stderr-64bit: "64 bits" -> "word size"
 //@ normalize-stderr-32bit: "32 bits" -> "word size"
+//@ normalize-stderr-64bit: "16 byte" -> "2 * word size"
+//@ normalize-stderr-32bit: "8 byte" -> "2 * word size"
 //@ normalize-stderr-64bit: "128 bits" -> "2 * word size"
 //@ normalize-stderr-32bit: "64 bits" -> "2 * word size"
 
@@ -10,4 +14,5 @@ fn main() {
 }
 
 const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
-//~^ ERROR cannot transmute between types of different sizes
+//~^ ERROR transmuting from
+//~| ERROR cannot transmute between types of different sizes
diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr
index 6bc7e7203aa..388cebc6884 100644
--- a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr
+++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr
@@ -1,5 +1,11 @@
+error[E0080]: transmuting from 8-byte type to 16-byte type: `usize` -> `&[u8]`
+  --> $DIR/transmute-size-mismatch-before-typeck.rs:16:29
+   |
+LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST` failed here
+
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/transmute-size-mismatch-before-typeck.rs:12:29
+  --> $DIR/transmute-size-mismatch-before-typeck.rs:16:29
    |
 LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
    |                             ^^^^^^^^^^^^^^^^^^^
@@ -7,6 +13,7 @@ LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
    = note: source type: `usize` (word size)
    = note: target type: `&[u8]` (2 * word size)
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0512`.
+Some errors have detailed explanations: E0080, E0512.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/impl-trait/transmute/in-defining-scope.rs b/tests/ui/impl-trait/transmute/in-defining-scope.rs
index 4c8e1852a91..d9eafcc553c 100644
--- a/tests/ui/impl-trait/transmute/in-defining-scope.rs
+++ b/tests/ui/impl-trait/transmute/in-defining-scope.rs
@@ -1,11 +1,12 @@
-// This causes a query cycle due to using `TypingEnv::PostAnalysis`,
+// Used to cause a query cycle due to using `TypingEnv::PostAnalysis`,
 // in #119821 const eval was changed to always use this mode.
 //
-// See that PR for more details.
+//@ check-pass
+
 use std::mem::transmute;
+
 fn foo() -> impl Sized {
-    //~^ ERROR cycle detected when computing type of
-    //~| WARN function cannot return without recursing
+    //~^ WARN function cannot return without recursing
     unsafe {
         transmute::<_, u8>(foo());
     }
diff --git a/tests/ui/impl-trait/transmute/in-defining-scope.stderr b/tests/ui/impl-trait/transmute/in-defining-scope.stderr
index 31535695178..015a39d6670 100644
--- a/tests/ui/impl-trait/transmute/in-defining-scope.stderr
+++ b/tests/ui/impl-trait/transmute/in-defining-scope.stderr
@@ -1,56 +1,5 @@
-error[E0391]: cycle detected when computing type of `foo::{opaque#0}`
-  --> $DIR/in-defining-scope.rs:6:13
-   |
-LL | fn foo() -> impl Sized {
-   |             ^^^^^^^^^^
-   |
-note: ...which requires computing type of opaque `foo::{opaque#0}`...
-  --> $DIR/in-defining-scope.rs:6:13
-   |
-LL | fn foo() -> impl Sized {
-   |             ^^^^^^^^^^
-note: ...which requires borrow-checking `foo`...
-  --> $DIR/in-defining-scope.rs:6:1
-   |
-LL | fn foo() -> impl Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `foo`...
-  --> $DIR/in-defining-scope.rs:6:1
-   |
-LL | fn foo() -> impl Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires checking if `foo` contains FFI-unwind calls...
-  --> $DIR/in-defining-scope.rs:6:1
-   |
-LL | fn foo() -> impl Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires building MIR for `foo`...
-  --> $DIR/in-defining-scope.rs:6:1
-   |
-LL | fn foo() -> impl Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires match-checking `foo`...
-  --> $DIR/in-defining-scope.rs:6:1
-   |
-LL | fn foo() -> impl Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires type-checking `foo`...
-  --> $DIR/in-defining-scope.rs:6:1
-   |
-LL | fn foo() -> impl Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing layout of `foo::{opaque#0}`...
-   = note: ...which requires normalizing `foo::{opaque#0}`...
-   = note: ...which again requires computing type of `foo::{opaque#0}`, completing the cycle
-note: cycle used when checking that `foo::{opaque#0}` is well-formed
-  --> $DIR/in-defining-scope.rs:6:13
-   |
-LL | fn foo() -> impl Sized {
-   |             ^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
 warning: function cannot return without recursing
-  --> $DIR/in-defining-scope.rs:6:1
+  --> $DIR/in-defining-scope.rs:8:1
    |
 LL | fn foo() -> impl Sized {
    | ^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -61,6 +10,5 @@ LL |         transmute::<_, u8>(foo());
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error: aborting due to 1 previous error; 1 warning emitted
+warning: 1 warning emitted
 
-For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.rs b/tests/ui/layout/base-layout-is-sized-ice-123078.rs
index b1c33e15075..bbe32b2022a 100644
--- a/tests/ui/layout/base-layout-is-sized-ice-123078.rs
+++ b/tests/ui/layout/base-layout-is-sized-ice-123078.rs
@@ -8,7 +8,9 @@ struct S {
 }
 
 const C: S = unsafe { std::mem::transmute(()) };
-//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
+//~^ ERROR the type `S` has an unknown layout
+//~| ERROR cannot transmute between types of different sizes, or dependently-sized types
+
 const _: [(); {
     C;
     0
diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
index d8743d4e6d6..d6cebd3e7ae 100644
--- a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
+++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
@@ -16,6 +16,12 @@ help: the `Box` type always has a statically known size and allocates its conten
 LL |     a: Box<[u8]>,
    |        ++++    +
 
+error[E0080]: the type `S` has an unknown layout
+  --> $DIR/base-layout-is-sized-ice-123078.rs:10:1
+   |
+LL | const C: S = unsafe { std::mem::transmute(()) };
+   | ^^^^^^^^^^ evaluation of `C` failed here
+
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/base-layout-is-sized-ice-123078.rs:10:23
    |
@@ -25,7 +31,7 @@ LL | const C: S = unsafe { std::mem::transmute(()) };
    = note: source type: `()` (0 bits)
    = note: target type: `S` (the type `S` has an unknown layout)
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0277, E0512.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0080, E0277, E0512.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/layout/normalization-failure.rs b/tests/ui/layout/normalization-failure.rs
index c0f8710c03c..a0195224d8c 100644
--- a/tests/ui/layout/normalization-failure.rs
+++ b/tests/ui/layout/normalization-failure.rs
@@ -49,8 +49,8 @@ fn check<T: Project1>() {
     unsafe {
         std::mem::transmute::<_, ()>(opaque::<T>().get());
         //~^ ERROR: cannot transmute
-        //~| NOTE: (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized)
-        //~| NOTE: (0 bits)
+        //~| NOTE: source type: `{type error}` (the type has an unknown layout)
+        //~| NOTE: target type: `()` (0 bits)
     }
 }
 
diff --git a/tests/ui/layout/normalization-failure.stderr b/tests/ui/layout/normalization-failure.stderr
index 5fe38d4403a..1c78fc6ac41 100644
--- a/tests/ui/layout/normalization-failure.stderr
+++ b/tests/ui/layout/normalization-failure.stderr
@@ -4,7 +4,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-
 LL |         std::mem::transmute::<_, ()>(opaque::<T>().get());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: source type: `<impl Project2 as Project2>::Assoc2` (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized)
+   = note: source type: `{type error}` (the type has an unknown layout)
    = note: target type: `()` (0 bits)
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/layout/transmute-to-tail-with-err.rs b/tests/ui/layout/transmute-to-tail-with-err.rs
index 6753ce15ed1..614c1ac756e 100644
--- a/tests/ui/layout/transmute-to-tail-with-err.rs
+++ b/tests/ui/layout/transmute-to-tail-with-err.rs
@@ -5,4 +5,5 @@ struct Bar(Box<dyn Trait<T>>);
 
 fn main() {
     let x: Bar = unsafe { std::mem::transmute(()) };
+    //~^ ERROR cannot transmute between types of different size
 }
diff --git a/tests/ui/layout/transmute-to-tail-with-err.stderr b/tests/ui/layout/transmute-to-tail-with-err.stderr
index 433c6b38d0b..cff40812717 100644
--- a/tests/ui/layout/transmute-to-tail-with-err.stderr
+++ b/tests/ui/layout/transmute-to-tail-with-err.stderr
@@ -9,6 +9,16 @@ help: you might be missing a type parameter
 LL | struct Bar<T>(Box<dyn Trait<T>>);
    |           +++
 
-error: aborting due to 1 previous error
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-to-tail-with-err.rs:7:27
+   |
+LL |     let x: Bar = unsafe { std::mem::transmute(()) };
+   |                           ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `()` (0 bits)
+   = note: target type: `Bar` (the type has an unknown layout)
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0412`.
+Some errors have detailed explanations: E0412, E0512.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.rs b/tests/ui/type-alias-impl-trait/issue-53092-2.rs
index 1a530d27971..4ddb06e40ff 100644
--- a/tests/ui/type-alias-impl-trait/issue-53092-2.rs
+++ b/tests/ui/type-alias-impl-trait/issue-53092-2.rs
@@ -2,11 +2,11 @@
 #![allow(dead_code)]
 
 type Bug<T, U> = impl Fn(T) -> U + Copy;
-//~^ ERROR cycle detected when computing type of `Bug::{opaque#0}`
 
 #[define_opaque(Bug)]
 const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
 //~^ ERROR item does not constrain `Bug::{opaque#0}`
+//~| ERROR: cannot transmute between types of different sizes, or dependently-sized types
 
 #[define_opaque(Bug)]
 fn make_bug<T, U: From<T>>() -> Bug<T, U> {
diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr
index c8db9fdfc57..689f7a733cb 100644
--- a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr
@@ -1,56 +1,5 @@
-error[E0391]: cycle detected when computing type of `Bug::{opaque#0}`
-  --> $DIR/issue-53092-2.rs:4:18
-   |
-LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of opaque `Bug::{opaque#0}`...
-  --> $DIR/issue-53092-2.rs:4:18
-   |
-LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires borrow-checking `CONST_BUG`...
-  --> $DIR/issue-53092-2.rs:8:1
-   |
-LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `CONST_BUG`...
-  --> $DIR/issue-53092-2.rs:8:1
-   |
-LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `CONST_BUG`...
-  --> $DIR/issue-53092-2.rs:8:1
-   |
-LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires building MIR for `CONST_BUG`...
-  --> $DIR/issue-53092-2.rs:8:1
-   |
-LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires match-checking `CONST_BUG`...
-  --> $DIR/issue-53092-2.rs:8:1
-   |
-LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires type-checking `CONST_BUG`...
-  --> $DIR/issue-53092-2.rs:8:1
-   |
-LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing layout of `Bug<u8, ()>`...
-   = note: ...which requires normalizing `Bug<u8, ()>`...
-   = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle
-note: cycle used when checking that `Bug::{opaque#0}` is well-formed
-  --> $DIR/issue-53092-2.rs:4:18
-   |
-LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
 error: item does not constrain `Bug::{opaque#0}`
-  --> $DIR/issue-53092-2.rs:8:7
+  --> $DIR/issue-53092-2.rs:7:7
    |
 LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
    |       ^^^^^^^^^
@@ -62,6 +11,15 @@ note: this opaque type is supposed to be constrained
 LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
    |                  ^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/issue-53092-2.rs:7:41
+   |
+LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
+   |                                         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `{closure@$DIR/issue-53092-2.rs:7:61: 7:68}` (0 bits)
+   = note: target type: `{type error}` (the type has an unknown layout)
+
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0391`.
+For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs
index 8e5e4719415..bd1d6651859 100644
--- a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs
+++ b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs
@@ -15,5 +15,6 @@ pub fn bar(x: Foo) -> Foo {
 fn main() {
     unsafe {
         let _: Foo = std::mem::transmute(0u8);
+        //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
     }
 }
diff --git a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr
index a57793d5a77..c9646a4e9a4 100644
--- a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr
+++ b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr
@@ -11,5 +11,15 @@ note: this opaque type is supposed to be constrained
 LL | pub type Foo = impl Copy;
    |                ^^^^^^^^^
 
-error: aborting due to 1 previous error
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/no_inferrable_concrete_type.rs:17:22
+   |
+LL |         let _: Foo = std::mem::transmute(0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `{type error}` (the type has an unknown layout)
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/type/pattern_types/or_patterns_invalid.rs b/tests/ui/type/pattern_types/or_patterns_invalid.rs
index d341927601d..a99667c5412 100644
--- a/tests/ui/type/pattern_types/or_patterns_invalid.rs
+++ b/tests/ui/type/pattern_types/or_patterns_invalid.rs
@@ -13,14 +13,18 @@ use std::pat::pattern_type;
 fn main() {
     //~? ERROR: only non-overlapping pattern type ranges are allowed at present
     let not_adjacent: pattern_type!(i8 is -127..0 | 1..) = unsafe { std::mem::transmute(0) };
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
 
     //~? ERROR: one pattern needs to end at `i8::MAX`, but was 29 instead
     let not_wrapping: pattern_type!(i8 is 10..20 | 20..30) = unsafe { std::mem::transmute(0) };
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
 
     //~? ERROR: only signed integer base types are allowed for or-pattern pattern types
     let not_signed: pattern_type!(u8 is 10.. | 0..5) = unsafe { std::mem::transmute(0) };
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
 
     //~? ERROR: allowed are two range patterns that are directly connected
     let not_simple_enough_for_mvp: pattern_type!(i8 is ..0 | 1..10 | 10..) =
         unsafe { std::mem::transmute(0) };
+        //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
 }
diff --git a/tests/ui/type/pattern_types/or_patterns_invalid.stderr b/tests/ui/type/pattern_types/or_patterns_invalid.stderr
index 6964788a6c2..e229c11386d 100644
--- a/tests/ui/type/pattern_types/or_patterns_invalid.stderr
+++ b/tests/ui/type/pattern_types/or_patterns_invalid.stderr
@@ -1,10 +1,47 @@
 error: only non-overlapping pattern type ranges are allowed at present
 
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/or_patterns_invalid.rs:15:69
+   |
+LL |     let not_adjacent: pattern_type!(i8 is -127..0 | 1..) = unsafe { std::mem::transmute(0) };
+   |                                                                     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `i32` (32 bits)
+   = note: target type: `(i8) is (-127..=-1 | 1..)` (the type has an unknown layout)
+
 error: one pattern needs to end at `i8::MAX`, but was 29 instead
 
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/or_patterns_invalid.rs:19:71
+   |
+LL |     let not_wrapping: pattern_type!(i8 is 10..20 | 20..30) = unsafe { std::mem::transmute(0) };
+   |                                                                       ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `i32` (32 bits)
+   = note: target type: `(i8) is (10..=19 | 20..=29)` (the type has an unknown layout)
+
 error: only signed integer base types are allowed for or-pattern pattern types at present
 
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/or_patterns_invalid.rs:23:65
+   |
+LL |     let not_signed: pattern_type!(u8 is 10.. | 0..5) = unsafe { std::mem::transmute(0) };
+   |                                                                 ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `i32` (32 bits)
+   = note: target type: `(u8) is (10.. | 0..=4)` (the type has an unknown layout)
+
 error: the only or-pattern types allowed are two range patterns that are directly connected at their overflow site
 
-error: aborting due to 4 previous errors
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/or_patterns_invalid.rs:28:18
+   |
+LL |         unsafe { std::mem::transmute(0) };
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `i32` (32 bits)
+   = note: target type: `(i8) is (i8::MIN..=-1 | 1..=9 | 10..)` (the type has an unknown layout)
+
+error: aborting due to 8 previous errors
 
+For more information about this error, try `rustc --explain E0512`.