@@ -1980,7 +1980,7 @@ macro_rules! transmute {
1980
1980
/// |
1981
1981
/// = note: source type: `AlignOf<[u8; 2]>` (8 bits)
1982
1982
/// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
1983
- /// = note: this error originates in the macro `zerocopy:: transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
1983
+ /// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro ` transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
1984
1984
/// ```
1985
1985
///
1986
1986
/// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
@@ -2011,7 +2011,8 @@ macro_rules! transmute_ref {
2011
2011
transmute( e)
2012
2012
} else if false {
2013
2013
// This branch, though never taken, ensures that `size_of::<T>() ==
2014
- // size_of::<U>()`.
2014
+ // size_of::<U>()` and that that `align_of::<T>() >=
2015
+ // align_of::<U>()`.
2015
2016
2016
2017
// `t` is inferred to have type `T` because it's assigned to `e` (of
2017
2018
// type `&T`) as `&t`.
@@ -2020,43 +2021,123 @@ macro_rules! transmute_ref {
2020
2021
2021
2022
// `u` is inferred to have type `U` because it's used as `&u` as the
2022
2023
// value returned from this branch.
2024
+ let u;
2025
+
2026
+ $crate:: assert_size_eq!( t, u) ;
2027
+ $crate:: assert_align_gt_eq!( t, u) ;
2028
+
2029
+ & u
2030
+ } else {
2031
+ // SAFETY:
2032
+ // - We know that the input and output types are both `Sized` (ie,
2033
+ // thin) references thanks to the trait bounds on `transmute`
2034
+ // above, and thanks to the fact that transmute takes and returns
2035
+ // references.
2036
+ // - We know that it is sound to view the target type of the input
2037
+ // reference (`T`) as the target type of the output reference
2038
+ // (`U`) because `T: AsBytes` and `U: FromBytes` (guaranteed by
2039
+ // trait bounds on `transmute`) and because `size_of::<T>() ==
2040
+ // size_of::<U>()` (guaranteed by the `assert_size_eq` above).
2041
+ // - We know that alignment is not increased thanks to the
2042
+ // `assert_align_gt_eq` above.
2023
2043
//
2024
- // SAFETY: This code is never run.
2025
- let u = unsafe {
2026
- // Clippy: It's okay to transmute a type to itself.
2044
+ // We use this reexport of `core::mem::transmute` because we know it
2045
+ // will always be available for crates which are using the 2015
2046
+ // edition of Rust. By contrast, if we were to use
2047
+ // `std::mem::transmute`, this macro would not work for such crates
2048
+ // in `no_std` contexts, and if we were to use
2049
+ // `core::mem::transmute`, this macro would not work in `std`
2050
+ // contexts in which `core` was not manually imported. This is not a
2051
+ // problem for 2018 edition crates.
2052
+ unsafe {
2053
+ // Clippy: It's okay to transmute a type to itself.
2027
2054
#[ allow( clippy:: useless_transmute) ]
2028
- $crate:: macro_util:: core_reexport:: mem:: transmute( t)
2029
- } ;
2030
- & u
2055
+ $crate:: macro_util:: core_reexport:: mem:: transmute( e)
2056
+ }
2057
+ }
2058
+ } }
2059
+ }
2060
+
2061
+ /// Safely transmutes a mutable reference of one type to an mutable reference of
2062
+ /// another type of the same size.
2063
+ ///
2064
+ /// The expression `$e` must have a concrete type, `&mut T`, where `T: Sized +
2065
+ /// AsBytes`. The `transmute_mut!` expression must also have a concrete type,
2066
+ /// `&mut U` (`U` is inferred from the calling context), where `U: Sized +
2067
+ /// FromBytes`. It must be the case that `align_of::<T>() >= align_of::<U>()`.
2068
+ ///
2069
+ /// The lifetime of the input type, `&mut T`, must be the same as or outlive the
2070
+ /// lifetime of the output type, `&mut U`.
2071
+ ///
2072
+ /// # Alignment increase error message
2073
+ ///
2074
+ /// Because of limitations on macros, the error message generated when
2075
+ /// `transmute_mut!` is used to transmute from a type of lower alignment to a
2076
+ /// type of higher alignment is somewhat confusing. For example, the following
2077
+ /// code:
2078
+ ///
2079
+ /// ```compile_fail
2080
+ /// const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]);
2081
+ /// ```
2082
+ ///
2083
+ /// ...generates the following error:
2084
+ ///
2085
+ /// ```text
2086
+ /// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
2087
+ /// --> src/lib.rs:1524:34
2088
+ /// |
2089
+ /// 5 | const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]);
2090
+ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2091
+ /// |
2092
+ /// = note: source type: `AlignOf<[u8; 2]>` (8 bits)
2093
+ /// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
2094
+ /// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
2095
+ /// ```
2096
+ ///
2097
+ /// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
2098
+ /// align_of::<T>()`, which is equivalent to `align_of::<T>() <
2099
+ /// align_of::<U>()`.
2100
+ #[ macro_export]
2101
+ macro_rules! transmute_mut {
2102
+ ( $e: expr) => { {
2103
+ // NOTE: This must be a macro (rather than a function with trait bounds)
2104
+ // because there's no way, in a generic context, to enforce that two
2105
+ // types have the same size or alignment.
2106
+
2107
+ let e = $e;
2108
+
2109
+ #[ allow( unused, clippy:: diverging_sub_expression) ]
2110
+ if false {
2111
+ // This branch, though never taken, ensures that the type of `e` is
2112
+ // `&mut T` where `T: 't + Sized + AsBytes + FromBytes`, that the
2113
+ // type of this macro expression is `&mut U` where `U: 'u + Sized +
2114
+ // AsBytes + FromBytes`.
2115
+ fn transmute<' t, T , U >( _t: & ' t mut T ) -> & ' t mut U
2116
+ where
2117
+ T : ' t + Sized + $crate:: AsBytes + $crate:: FromBytes ,
2118
+ U : ' t + Sized + $crate:: AsBytes + $crate:: FromBytes ,
2119
+ {
2120
+ loop { }
2121
+ }
2122
+ transmute( e)
2031
2123
} else if false {
2032
- // This branch, though never taken, ensures that the alignment of
2033
- // `T` is greater than or equal to to the alignment of `U`.
2124
+ // This branch, though never taken, ensures that `size_of::<T>() ==
2125
+ // size_of::<U>()` and that that `align_of::<T>() >=
2126
+ // align_of::<U>()`.
2034
2127
2035
2128
// `t` is inferred to have type `T` because it's assigned to `e` (of
2036
- // type `&T`) as `&t`.
2129
+ // type `&mut T`) as `&mut t`.
2037
2130
let mut t = unreachable!( ) ;
2038
- e = & t;
2131
+ e = & mut t;
2039
2132
2040
- // `u` is inferred to have type `U` because it's used as `&u` as the
2041
- // value returned from this branch.
2042
- let mut u = unreachable!( ) ;
2043
-
2044
- // The type wildcard in this bound is inferred to be `T` because
2045
- // `align_of.into_t()` is assigned to `t` (which has type `T`).
2046
- let align_of: $crate:: macro_util:: AlignOf <_> = unreachable!( ) ;
2047
- t = align_of. into_t( ) ;
2048
- // `max_aligns` is inferred to have type `MaxAlignsOf<T, U>` because
2049
- // of the inferred types of `t` and `u`.
2050
- let mut max_aligns = $crate:: macro_util:: MaxAlignsOf :: new( t, u) ;
2051
-
2052
- // This transmute will only compile successfully if
2053
- // `align_of::<T>() == max(align_of::<T>(), align_of::<U>())` - in
2054
- // other words, if `align_of::<T>() >= align_of::<U>()`.
2055
- //
2056
- // SAFETY: This code is never run.
2057
- max_aligns = unsafe { $crate:: macro_util:: core_reexport:: mem:: transmute( align_of) } ;
2133
+ // `u` is inferred to have type `U` because it's used as `&mut u` as
2134
+ // the value returned from this branch.
2135
+ let u;
2058
2136
2059
- & u
2137
+ $crate:: assert_size_eq!( t, u) ;
2138
+ $crate:: assert_align_gt_eq!( t, u) ;
2139
+
2140
+ & mut u
2060
2141
} else {
2061
2142
// SAFETY:
2062
2143
// - We know that the input and output types are both `Sized` (ie,
@@ -2065,13 +2146,12 @@ macro_rules! transmute_ref {
2065
2146
// references.
2066
2147
// - We know that it is sound to view the target type of the input
2067
2148
// reference (`T`) as the target type of the output reference
2068
- // (`U`) because `T: AsBytes` and `U: FromBytes` (guaranteed by
2069
- // trait bounds on `transmute`) and because `size_of::<T>() ==
2070
- // size_of::<U>()` (guaranteed by the first `core::mem::transmute`
2071
- // above).
2072
- // - We know that alignment is not increased thanks to the second
2073
- // `core::mem::transmute` above (the one which transmutes
2074
- // `MaxAlignsOf` into `AlignOf`).
2149
+ // (`U`) and visa versa because `T: AsBytes + FromBytes` and `U:
2150
+ // AsBytes + FromBytes` (guaranteed by trait bounds on
2151
+ // `transmute`) and because `size_of::<T>() == size_of::<U>()`
2152
+ // (guaranteed by the `assert_size_eq` above).
2153
+ // - We know that alignment is not increased thanks to the
2154
+ // `assert_align_gt_eq` above.
2075
2155
//
2076
2156
// We use this reexport of `core::mem::transmute` because we know it
2077
2157
// will always be available for crates which are using the 2015
@@ -4301,6 +4381,35 @@ mod tests {
4301
4381
assert_eq ! ( * y, 0 ) ;
4302
4382
}
4303
4383
4384
+ #[ test]
4385
+ fn test_transmute_mut ( ) {
4386
+ // Test that memory is transmuted as expected.
4387
+ let mut array_of_u8s = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
4388
+ let mut array_of_arrays = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
4389
+ let x: & mut [ [ u8 ; 2 ] ; 4 ] = transmute_mut ! ( & mut array_of_u8s) ;
4390
+ assert_eq ! ( * x, array_of_arrays) ;
4391
+ let x: & mut [ u8 ; 8 ] = transmute_mut ! ( & mut array_of_arrays) ;
4392
+ assert_eq ! ( * x, array_of_u8s) ;
4393
+
4394
+ {
4395
+ // Test that it's legal to transmute a reference while shrinking the
4396
+ // lifetime.
4397
+ let x: & mut [ u8 ; 8 ] = transmute_mut ! ( & mut array_of_arrays) ;
4398
+ assert_eq ! ( * x, array_of_u8s) ;
4399
+ }
4400
+ // Test that `transmute_mut!` supports decreasing alignment.
4401
+ let mut u = AU64 ( 0 ) ;
4402
+ let array = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
4403
+ let x: & [ u8 ; 8 ] = transmute_mut ! ( & mut u) ;
4404
+ assert_eq ! ( * x, array) ;
4405
+
4406
+ // Test that a mutable reference can be turned into an immutable one.
4407
+ let mut x = 0u8 ;
4408
+ #[ allow( clippy:: useless_transmute) ]
4409
+ let y: & u8 = transmute_mut ! ( & mut x) ;
4410
+ assert_eq ! ( * y, 0 ) ;
4411
+ }
4412
+
4304
4413
#[ test]
4305
4414
fn test_macros_evaluate_args_once ( ) {
4306
4415
let mut ctr = 0 ;
0 commit comments