Adjust transmute{,_copy} to be clearer about which of T and U is input vs output

This commit is contained in:
Thom Chiovoloni 2022-10-19 19:07:24 -07:00
parent 57781b24c5
commit afd08175de
No known key found for this signature in database
GPG Key ID: D7733D1D7A775F0A
4 changed files with 31 additions and 24 deletions

View File

@ -994,14 +994,14 @@ extern "rust-intrinsic" {
/// `transmute` is semantically equivalent to a bitwise move of one type /// `transmute` is semantically equivalent to a bitwise move of one type
/// into another. It copies the bits from the source value into the /// into another. It copies the bits from the source value into the
/// destination value, then forgets the original. Note that source and destination /// 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`. /// is *not* guaranteed to be preserved by `transmute`.
/// ///
/// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at /// 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 /// 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 /// 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 /// 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 /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly
/// unsafe**. `transmute` should be the absolute last resort. /// 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 /// 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 /// 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 /// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper
/// alignment of the pointed-to values. /// alignment of the pointed-to values.
/// ///
@ -1248,7 +1248,7 @@ extern "rust-intrinsic" {
#[rustc_allowed_through_unstable_modules] #[rustc_allowed_through_unstable_modules]
#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
#[rustc_diagnostic_item = "transmute"] #[rustc_diagnostic_item = "transmute"]
pub fn transmute<T, U>(e: T) -> U; pub fn transmute<Src, Dst>(src: Src) -> Dst;
/// Returns `true` if the actual type given as `T` requires drop /// Returns `true` if the actual type given as `T` requires drop
/// glue; returns `false` if the actual type provided for `T` /// glue; returns `false` if the actual type provided for `T`

View File

@ -1008,18 +1008,18 @@ pub fn copy<T: Copy>(x: &T) -> T {
*x *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. /// the contained value.
/// ///
/// This function will unsafely assume the pointer `src` is valid for [`size_of::<U>`][size_of] /// This function will unsafely assume the pointer `src` is valid for [`size_of::<Dst>`][size_of]
/// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way /// bytes by transmuting `&Src` to `&Dst` and then reading the `&Dst` (except that this is done
/// that is correct even when `&U` has stricter alignment requirements than `&T`). It will also /// in a way that is correct even when `&Dst` has stricter alignment requirements than `&Src`).
/// unsafely create a copy of the contained value instead of moving out of `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 /// 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 `T` and `U` have the /// is highly encouraged to only invoke this function where `Src` and `Dst` have the
/// same size. This function triggers [undefined behavior][ub] if `U` is larger than /// same size. This function triggers [undefined behavior][ub] if `Dst` is larger than
/// `T`. /// `Src`.
/// ///
/// [ub]: ../../reference/behavior-considered-undefined.html /// [ub]: ../../reference/behavior-considered-undefined.html
/// ///
@ -1052,19 +1052,22 @@ pub fn copy<T: Copy>(x: &T) -> T {
#[must_use] #[must_use]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
pub const unsafe fn transmute_copy<T, U>(src: &T) -> U { pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst {
assert!(size_of::<T>() >= size_of::<U>(), "cannot transmute_copy if U is larger than T"); assert!(
size_of::<Src>() >= size_of::<Dst>(),
"cannot transmute_copy if Dst is larger than Src"
);
// If U has a higher alignment requirement, src might not be suitably aligned. // If Dst has a higher alignment requirement, src might not be suitably aligned.
if align_of::<U>() > align_of::<T>() { if align_of::<Dst>() > align_of::<Src>() {
// SAFETY: `src` is a reference which is guaranteed to be valid for reads. // SAFETY: `src` is a reference which is guaranteed to be valid for reads.
// The caller must guarantee that the actual transmutation is safe. // 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 { } else {
// SAFETY: `src` is a reference which is guaranteed to be valid for reads. // 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. // 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) }
} }
} }

View File

@ -130,7 +130,11 @@ fn test_transmute_copy_grow_panics() {
payload payload
.downcast::<&'static str>() .downcast::<&'static str>()
.and_then(|s| { .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)); .unwrap_or_else(|p| panic::resume_unwind(p));
} }

View File

@ -2,12 +2,12 @@ error[E0282]: type annotations needed
--> $DIR/issue-6458-3.rs:4:5 --> $DIR/issue-6458-3.rs:4:5
| |
LL | mem::transmute(0); 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 help: consider specifying the generic arguments
| |
LL | mem::transmute::<i32, U>(0); LL | mem::transmute::<i32, Dst>(0);
| ++++++++++ | ++++++++++++
error: aborting due to previous error error: aborting due to previous error