@@ -1652,7 +1652,7 @@ macro_rules! transmute {
16521652            // `AsBytes` and that the type of this macro invocation expression 
16531653            // is `FromBytes`. 
16541654            const  fn  transmute<T :  $crate:: AsBytes ,  U :  $crate:: FromBytes >( _t:  T )  -> U  { 
1655-                 unreachable! ( ) 
1655+                 loop   { } 
16561656            } 
16571657            transmute( e) 
16581658        }  else { 
@@ -1669,7 +1669,154 @@ macro_rules! transmute {
16691669            // `core::mem::transmute`, this macro would not work in `std` 
16701670            // contexts in which `core` was not manually imported. This is not a 
16711671            // problem for 2018 edition crates. 
1672-             unsafe  {  $crate:: macro_util:: core_reexport:: mem:: transmute( e)  } 
1672+             unsafe  { 
1673+                 // Clippy: It's okay to transmute a type to itself. 
1674+                 #[ allow( clippy:: useless_transmute) ] 
1675+                 $crate:: macro_util:: core_reexport:: mem:: transmute( e) 
1676+             } 
1677+         } 
1678+     } } 
1679+ } 
1680+ 
1681+ /// Safely transmutes a mutable or immutable reference of one type to an 
1682+ /// immutable reference of another type of the same size. 
1683+ /// 
1684+ /// The expression `$e` must have a concrete type, `&T` or `&mut T`, where `T: 
1685+ /// Sized + AsBytes`. The `transmute_ref!` expression must also have a concrete 
1686+ /// type, `&U` (`U` is inferred from the calling context), where `U: Sized + 
1687+ /// FromBytes`. It must be the case that `align_of::<T>() >= align_of::<U>()`. 
1688+ /// 
1689+ /// The lifetime of the input type, `&T` or `&mut T`, must be the same as or 
1690+ /// outlive the lifetime of the output type, `&U`. 
1691+ /// 
1692+ /// # Alignment increase error message 
1693+ /// 
1694+ /// Because of limitations on macros, the error message generated when 
1695+ /// `transmute_ref!` is used to transmute from a type of lower alignment to a 
1696+ /// type of higher alignment is somewhat confusing. For example, the following 
1697+ /// code: 
1698+ /// 
1699+ /// ```compile_fail 
1700+ /// const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]); 
1701+ /// ``` 
1702+ /// 
1703+ /// ...generates the following error: 
1704+ /// 
1705+ /// ```text 
1706+ /// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types 
1707+ ///  --> src/lib.rs:1524:34 
1708+ ///   | 
1709+ /// 5 | const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]); 
1710+ ///   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
1711+ ///   | 
1712+ ///   = note: source type: `AlignOf<[u8; 2]>` (8 bits) 
1713+ ///   = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits) 
1714+ ///   = note: this error originates in the macro `zerocopy::transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) 
1715+ /// ``` 
1716+ /// 
1717+ /// This is saying that `max(align_of::<T>(), align_of::<U>()) != 
1718+ /// align_of::<T>()`, which is equivalent to `align_of::<T>() < 
1719+ /// align_of::<U>()`. 
1720+ #[ macro_export]  
1721+ macro_rules!  transmute_ref { 
1722+     ( $e: expr)  => { { 
1723+         // NOTE: This must be a macro (rather than a function with trait bounds) 
1724+         // because there's no way, in a generic context, to enforce that two 
1725+         // types have the same size or alignment. 
1726+ 
1727+         // Reborrow so that mutable references are supported too. 
1728+         // 
1729+         // In the rest of the comments, we refer only to `&T` since this 
1730+         // reborrow ensures that `e` is an immutable reference. 
1731+         let  e = & * $e; 
1732+ 
1733+         #[ allow( unused,  clippy:: diverging_sub_expression) ] 
1734+         if  false  { 
1735+             // This branch, though never taken, ensures that the type of `e` is 
1736+             // `&T` where `T: 't + Sized + AsBytes`, that the type of this macro 
1737+             // expression is `&U` where `U: 'u + Sized + FromBytes`, and that 
1738+             // `'t` outlives `'u`. 
1739+             const  fn  transmute<' u,  ' t:  ' u,  T :  ' t + Sized  + $crate:: AsBytes ,  U :  ' u + Sized  + $crate:: FromBytes >( _t:  & ' t T )  -> & ' u U  { 
1740+                 loop  { } 
1741+             } 
1742+             transmute( e) 
1743+         }  else if  false  { 
1744+             // This branch, though never taken, ensures that `size_of::<T>() == 
1745+             // size_of::<U>()`. 
1746+ 
1747+             // `t` is inferred to have type `T` because it's assigned to `e` (of 
1748+             // type `&T`) as `&t`. 
1749+             let  mut  t = unreachable!( ) ; 
1750+             e = & t; 
1751+ 
1752+             // `u` is inferred to have type `U` because it's used as `&u` as the 
1753+             // value returned from this branch. 
1754+             // 
1755+             // SAFETY: This code is never run. 
1756+             let  u = unsafe  { 
1757+                  // Clippy: It's okay to transmute a type to itself. 
1758+                 #[ allow( clippy:: useless_transmute) ] 
1759+                 $crate:: macro_util:: core_reexport:: mem:: transmute( t) 
1760+             } ; 
1761+             & u
1762+         }  else if  false  { 
1763+             // This branch, though never taken, ensures that the alignment of 
1764+             // `T` is greater than or equal to to the alignment of `U`. 
1765+ 
1766+             // `t` is inferred to have type `T` because it's assigned to `e` (of 
1767+             // type `&T`) as `&t`. 
1768+             let  mut  t = unreachable!( ) ; 
1769+             e = & t; 
1770+ 
1771+             // `u` is inferred to have type `U` because it's used as `&u` as the 
1772+             // value returned from this branch. 
1773+             let  mut  u = unreachable!( ) ; 
1774+ 
1775+             // The type wildcard in this bound is inferred to be `T` because 
1776+             // `align_of.into_t()` is assigned to `t` (which has type `T`). 
1777+             let  align_of:  $crate:: macro_util:: AlignOf <_> = unreachable!( ) ; 
1778+             t = align_of. into_t( ) ; 
1779+             // `max_aligns` is inferred to have type `MaxAlignsOf<T, U>` because 
1780+             // of the inferred types of `t` and `u`. 
1781+             let  mut  max_aligns = $crate:: macro_util:: MaxAlignsOf :: new( t,  u) ; 
1782+ 
1783+             // This transmute will only compile successfully if 
1784+             // `align_of::<T>() == max(align_of::<T>(), align_of::<U>())` - in 
1785+             // other words, if `align_of::<T>() >= align_of::<U>()`. 
1786+             // 
1787+             // SAFETY: This code is never run. 
1788+             max_aligns = unsafe  {  $crate:: macro_util:: core_reexport:: mem:: transmute( align_of)  } ; 
1789+ 
1790+             & u
1791+         }  else { 
1792+             // SAFETY: 
1793+             // - We know that the input and output types are both `Sized` (ie, 
1794+             //   thin) references thanks to the trait bounds on `transmute` 
1795+             //   above, and thanks to the fact that transmute takes and returns 
1796+             //   references. 
1797+             // - We know that it is sound to view the target type of the input 
1798+             //   reference (`T`) as the target type of the output reference 
1799+             //   (`U`) because `T: AsBytes` and `U: FromBytes` (guaranteed by 
1800+             //   trait bounds on `transmute`) and because `size_of::<T>() == 
1801+             //   size_of::<U>()` (guaranteed by the first `core::mem::transmute` 
1802+             //   above). 
1803+             // - We know that alignment is not increased thanks to the second 
1804+             //   `core::mem::transmute` above (the one which transmutes 
1805+             //   `MaxAlignsOf` into `AlignOf`). 
1806+             // 
1807+             // We use this reexport of `core::mem::transmute` because we know it 
1808+             // will always be available for crates which are using the 2015 
1809+             // edition of Rust. By contrast, if we were to use 
1810+             // `std::mem::transmute`, this macro would not work for such crates 
1811+             // in `no_std` contexts, and if we were to use 
1812+             // `core::mem::transmute`, this macro would not work in `std` 
1813+             // contexts in which `core` was not manually imported. This is not a 
1814+             // problem for 2018 edition crates. 
1815+             unsafe  { 
1816+                 // Clippy: It's okay to transmute a type to itself. 
1817+                 #[ allow( clippy:: useless_transmute) ] 
1818+                 $crate:: macro_util:: core_reexport:: mem:: transmute( e) 
1819+             } 
16731820        } 
16741821    } } 
16751822} 
@@ -3810,6 +3957,58 @@ mod tests {
38103957        assert_eq ! ( X ,  ARRAY_OF_ARRAYS ) ; 
38113958    } 
38123959
3960+     #[ test]  
3961+     fn  test_transmute_ref ( )  { 
3962+         // Test that memory is transmuted as expected. 
3963+         let  array_of_u8s = [ 0u8 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
3964+         let  array_of_arrays = [ [ 0 ,  1 ] ,  [ 2 ,  3 ] ,  [ 4 ,  5 ] ,  [ 6 ,  7 ] ] ; 
3965+         let  x:  & [ [ u8 ;  2 ] ;  4 ]  = transmute_ref ! ( & array_of_u8s) ; 
3966+         assert_eq ! ( * x,  array_of_arrays) ; 
3967+         let  x:  & [ u8 ;  8 ]  = transmute_ref ! ( & array_of_arrays) ; 
3968+         assert_eq ! ( * x,  array_of_u8s) ; 
3969+ 
3970+         // Test that `transmute_ref!` is legal in a const context. 
3971+         const  ARRAY_OF_U8S :  [ u8 ;  8 ]  = [ 0u8 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
3972+         const  ARRAY_OF_ARRAYS :  [ [ u8 ;  2 ] ;  4 ]  = [ [ 0 ,  1 ] ,  [ 2 ,  3 ] ,  [ 4 ,  5 ] ,  [ 6 ,  7 ] ] ; 
3973+         #[ allow( clippy:: redundant_static_lifetimes) ]  
3974+         const  X :  & ' static  [ [ u8 ;  2 ] ;  4 ]  = transmute_ref ! ( & ARRAY_OF_U8S ) ; 
3975+         assert_eq ! ( * X ,  ARRAY_OF_ARRAYS ) ; 
3976+ 
3977+         // Test that it's legal to transmute a reference while shrinking the 
3978+         // lifetime (note that `X` has the lifetime `'static`). 
3979+         let  x:  & [ u8 ;  8 ]  = transmute_ref ! ( X ) ; 
3980+         assert_eq ! ( * x,  ARRAY_OF_U8S ) ; 
3981+ 
3982+         // Test that `transmute_ref!` supports decreasing alignment. 
3983+         let  u = AU64 ( 0 ) ; 
3984+         let  array = [ 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ] ; 
3985+         let  x:  & [ u8 ;  8 ]  = transmute_ref ! ( & u) ; 
3986+         assert_eq ! ( * x,  array) ; 
3987+ 
3988+         // Test that a mutable reference can be turned into an immutable one. 
3989+         let  mut  x = 0u8 ; 
3990+         #[ allow( clippy:: useless_transmute) ]  
3991+         let  y:  & u8  = transmute_ref ! ( & mut  x) ; 
3992+         assert_eq ! ( * y,  0 ) ; 
3993+     } 
3994+ 
3995+     #[ test]  
3996+     fn  test_macros_evaluate_args_once ( )  { 
3997+         let  mut  ctr = 0 ; 
3998+         let  _:  usize  = transmute ! ( { 
3999+             ctr += 1 ; 
4000+             0usize 
4001+         } ) ; 
4002+         assert_eq ! ( ctr,  1 ) ; 
4003+ 
4004+         let  mut  ctr = 0 ; 
4005+         let  _:  & usize  = transmute_ref ! ( { 
4006+             ctr += 1 ; 
4007+             & 0usize 
4008+         } ) ; 
4009+         assert_eq ! ( ctr,  1 ) ; 
4010+     } 
4011+ 
38134012    #[ test]  
38144013    fn  test_address ( )  { 
38154014        // Test that the `Deref` and `DerefMut` implementations return a 
0 commit comments