From a3c878f813dd9c7c788cbe8d817699f2ef927e4e Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Thu, 14 Aug 2025 22:54:50 +0000 Subject: [PATCH 1/4] Separate transmute checking from typeck. --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 8 - compiler/rustc_hir_typeck/src/intrinsicck.rs | 207 +++++++++--------- compiler/rustc_hir_typeck/src/lib.rs | 5 +- compiler/rustc_hir_typeck/src/writeback.rs | 13 ++ compiler/rustc_interface/src/passes.rs | 3 +- compiler/rustc_middle/src/query/mod.rs | 5 + .../rustc_middle/src/ty/typeck_results.rs | 6 + tests/ui/const-generics/transmute-fail.stderr | 16 +- .../transmute-size-mismatch-before-typeck.rs | 7 +- ...ansmute-size-mismatch-before-typeck.stderr | 13 +- .../impl-trait/transmute/in-defining-scope.rs | 9 +- .../transmute/in-defining-scope.stderr | 56 +---- .../layout/base-layout-is-sized-ice-123078.rs | 4 +- .../base-layout-is-sized-ice-123078.stderr | 12 +- tests/ui/layout/normalization-failure.rs | 4 +- tests/ui/layout/normalization-failure.stderr | 2 +- tests/ui/layout/transmute-to-tail-with-err.rs | 1 + .../layout/transmute-to-tail-with-err.stderr | 14 +- .../ui/type-alias-impl-trait/issue-53092-2.rs | 2 +- .../issue-53092-2.stderr | 64 +----- .../no_inferrable_concrete_type.rs | 1 + .../no_inferrable_concrete_type.stderr | 12 +- .../type/pattern_types/or_patterns_invalid.rs | 4 + .../pattern_types/or_patterns_invalid.stderr | 39 +++- 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 b80a2af31007e..5aec50c8b5383 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 194e420b606ea..fffff7e6f8cf9 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`, 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` 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` 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 aae870f7ee3ee..ab4181f52932c 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 093de950d6369..42736a07b2a63 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 424cba2dae8bf..90f7ae7638756 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 3bb8353f49e84..d4f88c458a8db 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1115,6 +1115,11 @@ rustc_queries! { desc { |tcx| "collecting all inherent impls for `{:?}`", key } } + /// 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 6b187c5325a9b..f42dbbd2ac3d4 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>, + /// 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 0e26daa3a0f1e..953119a8c3413 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -6,6 +6,14 @@ LL | fn bar(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 ffb143da2d48b..17b343d2b9b76 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 6bc7e7203aa74..388cebc688403 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 4c8e1852a9104..d9eafcc553c45 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 3153569517835..015a39d6670ec 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 b1c33e1507551..bbe32b2022af0 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 d8743d4e6d63b..d6cebd3e7aee8 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 c0f8710c03cb3..a0195224d8ce1 100644 --- a/tests/ui/layout/normalization-failure.rs +++ b/tests/ui/layout/normalization-failure.rs @@ -49,8 +49,8 @@ fn check() { unsafe { std::mem::transmute::<_, ()>(opaque::().get()); //~^ ERROR: cannot transmute - //~| NOTE: (unable to determine layout for `::Assoc2` because `::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 5fe38d4403a20..1c78fc6ac41c4 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::().get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: source type: `::Assoc2` (unable to determine layout for `::Assoc2` because `::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 6753ce15ed158..614c1ac756e0b 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>); 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 433c6b38d0b42..cff408127179f 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(Box>); | +++ -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 1a530d27971a5..4ddb06e40fff3 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 = impl Fn(T) -> U + Copy; -//~^ ERROR cycle detected when computing type of `Bug::{opaque#0}` #[define_opaque(Bug)] const CONST_BUG: Bug = 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>() -> Bug { 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 c8db9fdfc579e..689f7a733cb5e 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 = 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 = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires borrow-checking `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug = 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 = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug = 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 = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires match-checking `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `Bug`... - = note: ...which requires normalizing `Bug`... - = 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 = 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 = unsafe { std::mem::transmute(|_: u8| ()) }; | ^^^^^^^^^ @@ -62,6 +11,15 @@ note: this opaque type is supposed to be constrained LL | type Bug = 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 = 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 8e5e47194153a..bd1d66518592c 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 a57793d5a7725..c9646a4e9a4d0 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 d341927601d50..a99667c5412ce 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 6964788a6c245..e229c11386d90 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`. From 9fe0b28db2439efa1a8147870c3e50f26f426ab5 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Fri, 15 Aug 2025 18:28:40 +0000 Subject: [PATCH 2/4] Simplify implementation. --- compiler/rustc_hir_typeck/src/intrinsicck.rs | 90 ++++++++++---------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index fffff7e6f8cf9..7567f8ba34883 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; 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_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use tracing::trace; @@ -38,6 +38,37 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { ty } +/// Try to display a sensible error with as much information as possible. +fn skeleton_string<'tcx>( + ty: Ty<'tcx>, + sk: Result, &'tcx LayoutError<'tcx>>, +) -> String { + 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)) => { + 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}") + } + } + Err(err) => err.to_string(), + } +} + fn check_transmute<'tcx>( tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, @@ -45,40 +76,36 @@ fn check_transmute<'tcx>( to: Ty<'tcx>, hir_id: HirId, ) { - let dl = &tcx.data_layout; - let span = tcx.hir_span(hir_id); + 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, + 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, typing_env); - let sk_from = skel(from); - let sk_to = skel(to); + let sk_from = SizeSkeleton::compute(from, tcx, typing_env); + let sk_to = SizeSkeleton::compute(to, tcx, typing_env); 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 let Ok(sk_from) = sk_from + && let Ok(sk_to) = sk_to + { if sk_from.same_size(sk_to) { return; } @@ -86,10 +113,11 @@ fn check_transmute<'tcx>( // Special-case transmuting from `typeof(function)` and // `Option` 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) + if let ty::FnDef(..) = from.kind() + && 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") + 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") @@ -98,35 +126,9 @@ fn check_transmute<'tcx>( } } - // 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)) => { - 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}") - } - } - Err(err) => err.to_string(), - }; - let mut err = struct_span_code_err!( tcx.sess.dcx(), - span, + span(), E0512, "cannot transmute between types of different sizes, or dependently-sized types" ); From 7494d927cb7a50bc3403f0ddaaf21e3fc710f3b7 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Fri, 15 Aug 2025 22:19:16 +0000 Subject: [PATCH 3/4] Fix stderr normalization. --- tests/ui/consts/transmute-size-mismatch-before-typeck.rs | 8 ++++---- .../consts/transmute-size-mismatch-before-typeck.stderr | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs index 17b343d2b9b76..4e0b12b902104 100644 --- a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs +++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs @@ -1,9 +1,9 @@ -//@ normalize-stderr-64bit: "8 byte" -> "word size" -//@ normalize-stderr-32bit: "4 byte" -> "word size" +//@ 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: "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" diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr index 388cebc688403..bb847f79ace8f 100644 --- a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr +++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -1,4 +1,4 @@ -error[E0080]: transmuting from 8-byte type to 16-byte type: `usize` -> `&[u8]` +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) }; From 0327e2b87e0df215a41a4b8c367c28b3dbdb3b22 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Fri, 22 Aug 2025 20:31:24 +0000 Subject: [PATCH 4/4] Bless rustdoc-ui. --- tests/rustdoc-ui/issues/issue-79494.rs | 5 +++-- tests/rustdoc-ui/issues/issue-79494.stderr | 9 +++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/rustdoc-ui/issues/issue-79494.rs b/tests/rustdoc-ui/issues/issue-79494.rs index 28ef82dac0f89..737c00a0269bb 100644 --- a/tests/rustdoc-ui/issues/issue-79494.rs +++ b/tests/rustdoc-ui/issues/issue-79494.rs @@ -1,5 +1,6 @@ -//@ only-x86_64-unknown-linux-gnu +//@ only-64bit #![feature(const_transmute)] -pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; //~ ERROR cannot transmute between types of different sizes, or dependently-sized types +pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; +//~^ ERROR transmuting from 8-byte type to 16-byte type diff --git a/tests/rustdoc-ui/issues/issue-79494.stderr b/tests/rustdoc-ui/issues/issue-79494.stderr index 20e568d8eaba1..fa797bfd50a69 100644 --- a/tests/rustdoc-ui/issues/issue-79494.stderr +++ b/tests/rustdoc-ui/issues/issue-79494.stderr @@ -1,12 +1,9 @@ -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types +error[E0080]: transmuting from 8-byte type to 16-byte type: `usize` -> `&[u8]` --> $DIR/issue-79494.rs:5:33 | LL | pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^ - | - = note: source type: `usize` (64 bits) - = note: target type: `&[u8]` (128 bits) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST` failed here error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0512`. +For more information about this error, try `rustc --explain E0080`.