@@ -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>()) !=
@@ -2020,13 +2020,10 @@ macro_rules! transmute_ref {
2020
2020
2021
2021
// `u` is inferred to have type `U` because it's used as `&u` as the
2022
2022
// value returned from this branch.
2023
- //
2024
- // SAFETY: This code is never run.
2025
- let u = unsafe {
2026
- // Clippy: It's okay to transmute a type to itself.
2027
- #[ allow( clippy:: useless_transmute) ]
2028
- $crate:: macro_util:: core_reexport:: mem:: transmute( t)
2029
- } ;
2023
+ let u;
2024
+
2025
+ $crate:: assert_size_eq!( t, u) ;
2026
+
2030
2027
& u
2031
2028
} else if false {
2032
2029
// This branch, though never taken, ensures that the alignment of
@@ -2041,20 +2038,7 @@ macro_rules! transmute_ref {
2041
2038
// value returned from this branch.
2042
2039
let mut u = unreachable!( ) ;
2043
2040
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) } ;
2041
+ $crate:: assert_align_gt_eq!( t, u) ;
2058
2042
2059
2043
& u
2060
2044
} else {
@@ -2067,11 +2051,139 @@ macro_rules! transmute_ref {
2067
2051
// reference (`T`) as the target type of the output reference
2068
2052
// (`U`) because `T: AsBytes` and `U: FromBytes` (guaranteed by
2069
2053
// 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`).
2054
+ // size_of::<U>()` (guaranteed by the `assert_size_eq` above).
2055
+ // - We know that alignment is not increased thanks to the
2056
+ // `assert_align_gt_eq` above.
2057
+ //
2058
+ // We use this reexport of `core::mem::transmute` because we know it
2059
+ // will always be available for crates which are using the 2015
2060
+ // edition of Rust. By contrast, if we were to use
2061
+ // `std::mem::transmute`, this macro would not work for such crates
2062
+ // in `no_std` contexts, and if we were to use
2063
+ // `core::mem::transmute`, this macro would not work in `std`
2064
+ // contexts in which `core` was not manually imported. This is not a
2065
+ // problem for 2018 edition crates.
2066
+ unsafe {
2067
+ // Clippy: It's okay to transmute a type to itself.
2068
+ #[ allow( clippy:: useless_transmute) ]
2069
+ $crate:: macro_util:: core_reexport:: mem:: transmute( e)
2070
+ }
2071
+ }
2072
+ } }
2073
+ }
2074
+
2075
+ /// Safely transmutes a mutable reference of one type to an mutable reference of
2076
+ /// another type of the same size.
2077
+ ///
2078
+ /// The expression `$e` must have a concrete type, `&mut T`, where `T: Sized +
2079
+ /// AsBytes`. The `transmute_mut!` expression must also have a concrete type,
2080
+ /// `&mut U` (`U` is inferred from the calling context), where `U: Sized +
2081
+ /// FromBytes`. It must be the case that `align_of::<T>() >= align_of::<U>()`.
2082
+ ///
2083
+ /// The lifetime of the input type, `&mut T`, must be the same as or outlive the
2084
+ /// lifetime of the output type, `&mut U`.
2085
+ ///
2086
+ /// # Alignment increase error message
2087
+ ///
2088
+ /// Because of limitations on macros, the error message generated when
2089
+ /// `transmute_mut!` is used to transmute from a type of lower alignment to a
2090
+ /// type of higher alignment is somewhat confusing. For example, the following
2091
+ /// code:
2092
+ ///
2093
+ /// ```compile_fail
2094
+ /// const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]);
2095
+ /// ```
2096
+ ///
2097
+ /// ...generates the following error:
2098
+ ///
2099
+ /// ```text
2100
+ /// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
2101
+ /// --> src/lib.rs:1524:34
2102
+ /// |
2103
+ /// 5 | const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]);
2104
+ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2105
+ /// |
2106
+ /// = note: source type: `AlignOf<[u8; 2]>` (8 bits)
2107
+ /// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
2108
+ /// = 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)
2109
+ /// ```
2110
+ ///
2111
+ /// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
2112
+ /// align_of::<T>()`, which is equivalent to `align_of::<T>() <
2113
+ /// align_of::<U>()`.
2114
+ #[ macro_export]
2115
+ macro_rules! transmute_mut {
2116
+ ( $e: expr) => { {
2117
+ // NOTE: This must be a macro (rather than a function with trait bounds)
2118
+ // because there's no way, in a generic context, to enforce that two
2119
+ // types have the same size or alignment.
2120
+
2121
+ // Reborrow so that mutable references are supported too.
2122
+ //
2123
+ // In the rest of the comments, we refer only to `&T` since this
2124
+ // reborrow ensures that `e` is an immutable reference.
2125
+ let e = & mut * $e;
2126
+
2127
+ #[ allow( unused, clippy:: diverging_sub_expression) ]
2128
+ if false {
2129
+ // This branch, though never taken, ensures that the type of `e` is
2130
+ // `&mut T` where `T: 't + Sized + AsBytes + FromBytes`, that the
2131
+ // type of this macro expression is `&mut U` where `U: 'u + Sized +
2132
+ // AsBytes + FromBytes`.
2133
+ fn transmute<' t, T , U >( _t: & ' t mut T ) -> & ' t mut U
2134
+ where
2135
+ T : ' t + Sized + $crate:: AsBytes + $crate:: FromBytes ,
2136
+ U : ' t + Sized + $crate:: AsBytes + $crate:: FromBytes ,
2137
+ {
2138
+ loop { }
2139
+ }
2140
+ transmute( & mut * e)
2141
+ } else if false {
2142
+ // This branch, though never taken, ensures that `size_of::<T>() ==
2143
+ // size_of::<U>()`.
2144
+
2145
+ // `t` is inferred to have type `T` because it's assigned to `e` (of
2146
+ // type `&mut T`) as `&mut t`.
2147
+ let mut t = unreachable!( ) ;
2148
+ e = & mut t;
2149
+
2150
+ // `u` is inferred to have type `U` because it's used as `&mut u` as
2151
+ // the value returned from this branch.
2152
+ let u;
2153
+
2154
+ $crate:: assert_size_eq!( t, u) ;
2155
+
2156
+ & mut u
2157
+ } else if false {
2158
+ // This branch, though never taken, ensures that the alignment of
2159
+ // `T` is greater than or equal to to the alignment of `U`.
2160
+
2161
+ // `t` is inferred to have type `T` because it's assigned to `e` (of
2162
+ // type `&mut T`) as `&mut t`.
2163
+ let mut t = unreachable!( ) ;
2164
+ e = & mut t;
2165
+
2166
+ // `u` is inferred to have type `U` because it's used as `&mut u` as
2167
+ // the value returned from this branch.
2168
+ let mut u = unreachable!( ) ;
2169
+
2170
+ $crate:: assert_align_gt_eq!( t, u) ;
2171
+
2172
+ & mut u
2173
+ } else {
2174
+ // SAFETY:
2175
+ // - We know that the input and output types are both `Sized` (ie,
2176
+ // thin) references thanks to the trait bounds on `transmute`
2177
+ // above, and thanks to the fact that transmute takes and returns
2178
+ // references.
2179
+ // - We know that it is sound to view the target type of the input
2180
+ // reference (`T`) as the target type of the output reference
2181
+ // (`U`) and visa versa because `T: AsBytes + FromBytes` and `U:
2182
+ // AsBytes + FromBytes` (guaranteed by trait bounds on
2183
+ // `transmute`) and because `size_of::<T>() == size_of::<U>()`
2184
+ // (guaranteed by the `assert_size_eq` above).
2185
+ // - We know that alignment is not increased thanks to the
2186
+ // `assert_align_gt_eq` above.
2075
2187
//
2076
2188
// We use this reexport of `core::mem::transmute` because we know it
2077
2189
// will always be available for crates which are using the 2015
@@ -4301,6 +4413,35 @@ mod tests {
4301
4413
assert_eq ! ( * y, 0 ) ;
4302
4414
}
4303
4415
4416
+ #[ test]
4417
+ fn test_transmute_mut ( ) {
4418
+ // Test that memory is transmuted as expected.
4419
+ let mut array_of_u8s = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
4420
+ let mut array_of_arrays = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
4421
+ let x: & mut [ [ u8 ; 2 ] ; 4 ] = transmute_mut ! ( & mut array_of_u8s) ;
4422
+ assert_eq ! ( * x, array_of_arrays) ;
4423
+ let x: & mut [ u8 ; 8 ] = transmute_mut ! ( & mut array_of_arrays) ;
4424
+ assert_eq ! ( * x, array_of_u8s) ;
4425
+
4426
+ {
4427
+ // Test that it's legal to transmute a reference while shrinking the
4428
+ // lifetime.
4429
+ let x: & mut [ u8 ; 8 ] = transmute_mut ! ( & mut array_of_arrays) ;
4430
+ assert_eq ! ( * x, array_of_u8s) ;
4431
+ }
4432
+ // Test that `transmute_mut!` supports decreasing alignment.
4433
+ let mut u = AU64 ( 0 ) ;
4434
+ let array = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
4435
+ let x: & [ u8 ; 8 ] = transmute_mut ! ( & mut u) ;
4436
+ assert_eq ! ( * x, array) ;
4437
+
4438
+ // Test that a mutable reference can be turned into an immutable one.
4439
+ let mut x = 0u8 ;
4440
+ #[ allow( clippy:: useless_transmute) ]
4441
+ let y: & u8 = transmute_mut ! ( & mut x) ;
4442
+ assert_eq ! ( * y, 0 ) ;
4443
+ }
4444
+
4304
4445
#[ test]
4305
4446
fn test_macros_evaluate_args_once ( ) {
4306
4447
let mut ctr = 0 ;
0 commit comments