From 568e49d8d7ded47ec323ec3eb4a4915c3cffc3c1 Mon Sep 17 00:00:00 2001 From: human9000 Date: Fri, 20 Mar 2026 16:28:08 +0500 Subject: [PATCH 1/5] Make `check_transmutes` query return `Result` --- compiler/rustc_hir_typeck/src/intrinsicck.rs | 23 +++++++++++-------- compiler/rustc_middle/src/queries.rs | 2 +- tests/ui/transmute/transmute-in-async-fn.rs | 6 +++++ .../ui/transmute/transmute-in-async-fn.stderr | 12 ++++++++++ 4 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 tests/ui/transmute/transmute-in-async-fn.rs create mode 100644 tests/ui/transmute/transmute-in-async-fn.stderr diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 7d2a00c435cb7..763d8875bff78 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -8,6 +8,7 @@ use rustc_index::Idx; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; use rustc_middle::ty::{self, Ty, TyCtxt, Unnormalized}; +use rustc_span::ErrorGuaranteed; use rustc_span::def_id::LocalDefId; use tracing::trace; @@ -72,7 +73,7 @@ fn check_transmute<'tcx>( from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId, -) { +) -> Result<(), ErrorGuaranteed> { let span = || tcx.hir_span(hir_id); let normalize = |ty| { if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)) { @@ -92,7 +93,7 @@ fn check_transmute<'tcx>( // Transmutes that are only changing lifetimes are always ok. if from == to { - return; + return Ok(()); } let sk_from = SizeSkeleton::compute(from, tcx, typing_env); @@ -104,7 +105,7 @@ fn check_transmute<'tcx>( && let Ok(sk_to) = sk_to { if sk_from.same_size(sk_to) { - return; + return Ok(()); } // Special-case transmuting from `typeof(function)` and @@ -119,7 +120,7 @@ fn check_transmute<'tcx>( .with_note(format!("target type: {to}")) .with_help("cast with `as` to a pointer instead") .emit(); - return; + return Ok(()); } } @@ -131,21 +132,25 @@ fn check_transmute<'tcx>( ); if from == to { err.note(format!("`{from}` does not have a fixed size")); - err.emit(); + Err(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(); + Err(err.emit()) } } -pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) { +pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), ErrorGuaranteed> { assert!(!tcx.is_typeck_child(owner.to_def_id())); let typeck_results = tcx.typeck(owner); - let None = typeck_results.tainted_by_errors else { return }; + if let Some(e) = typeck_results.tainted_by_errors { + return Err(e); + }; let typing_env = ty::TypingEnv::post_analysis(tcx, owner); + let mut result = Ok(()); for &(from, to, hir_id) in &typeck_results.transmutes_to_check { - check_transmute(tcx, typing_env, from, to, hir_id); + result = check_transmute(tcx, typing_env, from, to, hir_id); } + result } diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 7c6ab642b2736..fdc287a3f2607 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -1138,7 +1138,7 @@ rustc_queries! { } /// Unsafety-check this `LocalDefId`. - query check_transmutes(key: LocalDefId) { + query check_transmutes(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { "check transmute calls inside `{}`", tcx.def_path_str(key) } } diff --git a/tests/ui/transmute/transmute-in-async-fn.rs b/tests/ui/transmute/transmute-in-async-fn.rs new file mode 100644 index 0000000000000..be2df3bdca084 --- /dev/null +++ b/tests/ui/transmute/transmute-in-async-fn.rs @@ -0,0 +1,6 @@ +//@compile-flags: -Zmir-enable-passes=+DataflowConstProp --crate-type lib +//@ edition:2021 +pub async fn a() -> u32 { + unsafe { std::mem::transmute(1u64) } + //~^error: cannot transmute between types of different sizes, or dependently-sized types +} diff --git a/tests/ui/transmute/transmute-in-async-fn.stderr b/tests/ui/transmute/transmute-in-async-fn.stderr new file mode 100644 index 0000000000000..845c6387bdfd5 --- /dev/null +++ b/tests/ui/transmute/transmute-in-async-fn.stderr @@ -0,0 +1,12 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-in-async-fn.rs:4:14 + | +LL | unsafe { std::mem::transmute(1u64) } + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u64` (64 bits) + = note: target type: `u32` (32 bits) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0512`. From 70116e15f009f46f6774c18ee4da397caaa5229f Mon Sep 17 00:00:00 2001 From: human9000 Date: Wed, 15 Apr 2026 16:52:49 +0500 Subject: [PATCH 2/5] Update transmute test for typeck child cases --- tests/ui/transmute/transmute-in-async-fn.rs | 6 ++++++ tests/ui/transmute/transmute-in-async-fn.stderr | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/ui/transmute/transmute-in-async-fn.rs b/tests/ui/transmute/transmute-in-async-fn.rs index be2df3bdca084..83574ee5b8bde 100644 --- a/tests/ui/transmute/transmute-in-async-fn.rs +++ b/tests/ui/transmute/transmute-in-async-fn.rs @@ -4,3 +4,9 @@ pub async fn a() -> u32 { unsafe { std::mem::transmute(1u64) } //~^error: cannot transmute between types of different sizes, or dependently-sized types } + +pub async fn b() -> u32 { + let closure = || unsafe { std::mem::transmute(1u64) }; + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types [E0512] + closure() +} diff --git a/tests/ui/transmute/transmute-in-async-fn.stderr b/tests/ui/transmute/transmute-in-async-fn.stderr index 845c6387bdfd5..2f5e471302b51 100644 --- a/tests/ui/transmute/transmute-in-async-fn.stderr +++ b/tests/ui/transmute/transmute-in-async-fn.stderr @@ -7,6 +7,15 @@ LL | unsafe { std::mem::transmute(1u64) } = note: source type: `u64` (64 bits) = note: target type: `u32` (32 bits) -error: aborting due to 1 previous error +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-in-async-fn.rs:9:31 + | +LL | let closure = || unsafe { std::mem::transmute(1u64) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u64` (64 bits) + = note: target type: `u32` (32 bits) + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0512`. From 788c91688b555d03f3b9a425bd68beab9d6e82b4 Mon Sep 17 00:00:00 2001 From: human9000 Date: Wed, 15 Apr 2026 17:25:28 +0500 Subject: [PATCH 3/5] Taint the body in case of malformed transmutes --- compiler/rustc_mir_transform/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 9273c2103d442..ce30c54f5032b 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -550,11 +550,15 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & body.tainted_by_errors = Some(error_reported); } + let root = tcx.typeck_root_def_id_local(def); + if let Err(e) = tcx.check_transmutes(root) { + body.tainted_by_errors = Some(e); + } + // Also taint the body if it's within a top-level item that is not well formed. // // We do this check here and not during `mir_promoted` because that may result // in borrowck cycles if WF requires looking into an opaque hidden type. - let root = tcx.typeck_root_def_id_local(def); match tcx.def_kind(root) { DefKind::Fn | DefKind::AssocFn From 6f08425386870f8c65d2b6082652c410604d84cc Mon Sep 17 00:00:00 2001 From: human9000 Date: Wed, 15 Apr 2026 20:51:52 +0500 Subject: [PATCH 4/5] Fix error handling in `check_transmutes` --- compiler/rustc_hir_typeck/src/intrinsicck.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 763d8875bff78..9ee3764dc94a1 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -115,12 +115,17 @@ fn check_transmute<'tcx>( && let SizeSkeleton::Known(size_to, _) = sk_to && size_to == Pointer(tcx.data_layout.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 Ok(()); + let err = 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 Err(err); } } @@ -150,7 +155,7 @@ pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), let typing_env = ty::TypingEnv::post_analysis(tcx, owner); let mut result = Ok(()); for &(from, to, hir_id) in &typeck_results.transmutes_to_check { - result = check_transmute(tcx, typing_env, from, to, hir_id); + result = result.and(check_transmute(tcx, typing_env, from, to, hir_id)); } result } From 694c13815cddd5f6f22f0972109f1196a1ca4ebc Mon Sep 17 00:00:00 2001 From: human9000 Date: Tue, 21 Apr 2026 17:24:28 +0500 Subject: [PATCH 5/5] bless tests where error messages disappeared because of body tainting --- tests/rustdoc-ui/issues/issue-79494.rs | 2 +- tests/rustdoc-ui/issues/issue-79494.stderr | 9 ++++++--- .../consts/transmute-size-mismatch-before-typeck.rs | 3 +-- .../transmute-size-mismatch-before-typeck.stderr | 11 ++--------- tests/ui/layout/base-layout-is-sized-ice-123078.rs | 3 +-- .../ui/layout/base-layout-is-sized-ice-123078.stderr | 12 +++--------- 6 files changed, 14 insertions(+), 26 deletions(-) diff --git a/tests/rustdoc-ui/issues/issue-79494.rs b/tests/rustdoc-ui/issues/issue-79494.rs index c80e0a9842136..02df594c4ec90 100644 --- a/tests/rustdoc-ui/issues/issue-79494.rs +++ b/tests/rustdoc-ui/issues/issue-79494.rs @@ -1,4 +1,4 @@ //@ only-64bit pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; -//~^ ERROR transmuting from 8-byte type to 16-byte type +//~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types [E0512] diff --git a/tests/rustdoc-ui/issues/issue-79494.stderr b/tests/rustdoc-ui/issues/issue-79494.stderr index 31ed8f18ab07c..6e8294114a69b 100644 --- a/tests/rustdoc-ui/issues/issue-79494.stderr +++ b/tests/rustdoc-ui/issues/issue-79494.stderr @@ -1,9 +1,12 @@ -error[E0080]: transmuting from 8-byte type to 16-byte type: `usize` -> `&[u8]` +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/issue-79494.rs:3:33 | LL | pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST` failed here + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `usize` (64 bits) + = note: target type: `&[u8]` (128 bits) error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs index 4e0b12b902104..7b2f7126aa6a0 100644 --- a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs +++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs @@ -14,5 +14,4 @@ fn main() { } const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; -//~^ ERROR transmuting from -//~| ERROR cannot transmute between types of different sizes +//~^ 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 bb847f79ace8f..889aec2671d4a 100644 --- a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr +++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -1,9 +1,3 @@ -error[E0080]: transmuting from word size type to 2 * word size 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:16:29 | @@ -13,7 +7,6 @@ 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 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0080, E0512. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0512`. 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 bbe32b2022af0..e7bfe0f86d6a0 100644 --- a/tests/ui/layout/base-layout-is-sized-ice-123078.rs +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.rs @@ -8,8 +8,7 @@ struct S { } const C: S = unsafe { std::mem::transmute(()) }; -//~^ ERROR the type `S` has an unknown layout -//~| ERROR cannot transmute between types of different sizes, or dependently-sized types +//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types const _: [(); { C; 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 d6cebd3e7aee8..d8743d4e6d63b 100644 --- a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr @@ -16,12 +16,6 @@ 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 | @@ -31,7 +25,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 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0080, E0277, E0512. -For more information about an error, try `rustc --explain E0080`. +Some errors have detailed explanations: E0277, E0512. +For more information about an error, try `rustc --explain E0277`.