From afd08175de04e890ec542b02d2b72a7b525e86d6 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 19 Oct 2022 19:07:24 -0700 Subject: [PATCH] Adjust `transmute{,_copy}` to be clearer about which of `T` and `U` is input vs output --- library/core/src/intrinsics.rs | 8 +++--- library/core/src/mem/mod.rs | 35 ++++++++++++++------------ library/core/tests/mem.rs | 6 ++++- src/test/ui/issues/issue-6458-3.stderr | 6 ++--- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 2399262c05b46..1589fee46bee6 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -994,14 +994,14 @@ extern "rust-intrinsic" { /// `transmute` is semantically equivalent to a bitwise move of one type /// into another. It copies the bits from the source value into the /// destination value, then forgets the original. Note that source and destination - /// are passed by-value, which means if `T` or `U` contain padding, that padding + /// are passed by-value, which means if `Src` or `Dst` contain padding, that padding /// is *not* guaranteed to be preserved by `transmute`. /// /// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at /// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler /// will generate code *assuming that you, the programmer, ensure that there will never be /// undefined behavior*. It is therefore your responsibility to guarantee that every value - /// passed to `transmute` is valid at both types `T` and `U`. Failing to uphold this condition + /// passed to `transmute` is valid at both types `Src` and `Dst`. Failing to uphold this condition /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly /// unsafe**. `transmute` should be the absolute last resort. /// @@ -1012,7 +1012,7 @@ extern "rust-intrinsic" { /// /// Because `transmute` is a by-value operation, alignment of the *transmuted values /// themselves* is not a concern. As with any other function, the compiler already ensures - /// both `T` and `U` are properly aligned. However, when transmuting values that *point + /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point /// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper /// alignment of the pointed-to values. /// @@ -1248,7 +1248,7 @@ extern "rust-intrinsic" { #[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_diagnostic_item = "transmute"] - pub fn transmute(e: T) -> U; + pub fn transmute(src: Src) -> Dst; /// Returns `true` if the actual type given as `T` requires drop /// glue; returns `false` if the actual type provided for `T` diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 1a78efaf4ffad..9195da5a44f42 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1008,18 +1008,18 @@ pub fn copy(x: &T) -> T { *x } -/// Interprets `src` as having type `&U`, and then reads `src` without moving +/// Interprets `src` as having type `&Dst`, and then reads `src` without moving /// the contained value. /// -/// This function will unsafely assume the pointer `src` is valid for [`size_of::`][size_of] -/// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way -/// that is correct even when `&U` has stricter alignment requirements than `&T`). It will also -/// unsafely create a copy of the contained value instead of moving out of `src`. +/// This function will unsafely assume the pointer `src` is valid for [`size_of::`][size_of] +/// bytes by transmuting `&Src` to `&Dst` and then reading the `&Dst` (except that this is done +/// in a way that is correct even when `&Dst` has stricter alignment requirements than `&Src`). +/// It will also unsafely create a copy of the contained value instead of moving out of `src`. /// -/// It is not a compile-time error if `T` and `U` have different sizes, but it -/// is highly encouraged to only invoke this function where `T` and `U` have the -/// same size. This function triggers [undefined behavior][ub] if `U` is larger than -/// `T`. +/// It is not a compile-time error if `Src` and `Dst` have different sizes, but it +/// is highly encouraged to only invoke this function where `Src` and `Dst` have the +/// same size. This function triggers [undefined behavior][ub] if `Dst` is larger than +/// `Src`. /// /// [ub]: ../../reference/behavior-considered-undefined.html /// @@ -1052,19 +1052,22 @@ pub fn copy(x: &T) -> T { #[must_use] #[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"); +pub const unsafe fn transmute_copy(src: &Src) -> Dst { + assert!( + size_of::() >= size_of::(), + "cannot transmute_copy if Dst is larger than Src" + ); - // If U has a higher alignment requirement, src might not be suitably aligned. - if align_of::() > align_of::() { + // If Dst 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. // The caller must guarantee that the actual transmutation is safe. - unsafe { ptr::read_unaligned(src as *const T as *const U) } + unsafe { ptr::read_unaligned(src as *const Src as *const Dst) } } else { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. - // We just checked that `src as *const U` was properly aligned. + // We just checked that `src as *const Dst` was properly aligned. // The caller must guarantee that the actual transmutation is safe. - unsafe { ptr::read(src as *const T as *const U) } + unsafe { ptr::read(src as *const Src as *const Dst) } } } diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index b0cc08a15f0a0..0362e1c8afb5e 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -130,7 +130,11 @@ fn test_transmute_copy_grow_panics() { payload .downcast::<&'static str>() .and_then(|s| { - if *s == "cannot transmute_copy if U is larger than T" { Ok(s) } else { Err(s) } + if *s == "cannot transmute_copy if Dst is larger than Src" { + Ok(s) + } else { + Err(s) + } }) .unwrap_or_else(|p| panic::resume_unwind(p)); } diff --git a/src/test/ui/issues/issue-6458-3.stderr b/src/test/ui/issues/issue-6458-3.stderr index 2c3ec1a331ff8..520efccae51c4 100644 --- a/src/test/ui/issues/issue-6458-3.stderr +++ b/src/test/ui/issues/issue-6458-3.stderr @@ -2,12 +2,12 @@ error[E0282]: type annotations needed --> $DIR/issue-6458-3.rs:4:5 | LL | mem::transmute(0); - | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `transmute` + | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `Dst` declared on the function `transmute` | help: consider specifying the generic arguments | -LL | mem::transmute::(0); - | ++++++++++ +LL | mem::transmute::(0); + | ++++++++++++ error: aborting due to previous error