diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index ecd2b75ae44..66af4916074 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1040,6 +1040,8 @@ pub fn copy(x: &T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] pub const unsafe fn transmute_copy(src: &T) -> U { + assert!(size_of::() >= size_of::(), "cannot transmute_copy if U is larger than T"); + // If U has a higher alignment requirement, src might not be suitably aligned. if align_of::() > align_of::() { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 3b13dc0832f..6856d1a1f51 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -97,6 +97,46 @@ fn test_transmute_copy() { assert_eq!(1, unsafe { transmute_copy(&1) }); } +#[test] +fn test_transmute_copy_shrink() { + assert_eq!(0_u8, unsafe { transmute_copy(&0_u64) }); +} + +#[test] +fn test_transmute_copy_unaligned() { + #[repr(C)] + #[derive(Default)] + struct Unaligned { + a: u8, + b: [u8; 8], + } + + let u = Unaligned::default(); + assert_eq!(0_u64, unsafe { transmute_copy(&u.b) }); +} + +#[test] +#[cfg(panic = "unwind")] +fn test_transmute_copy_grow_panics() { + use std::panic; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { + let _unused: u64 = transmute_copy(&1_u8); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| { + if *s == "cannot transmute_copy if U is larger than T" { Ok(s) } else { Err(s) } + }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + } + } +} + #[test] #[allow(dead_code)] fn test_discriminant_send_sync() {