5151/// This macro can be invoked in `const` contexts.
5252#[ macro_export]
5353macro_rules! transmute {
54- ( $e: expr) => { {
55- // NOTE: This must be a macro (rather than a function with trait bounds)
56- // because there's no way, in a generic context, to enforce that two
57- // types have the same size. `core::mem::transmute` uses compiler magic
58- // to enforce this so long as the types are concrete.
59-
60- let e = $e;
54+ // NOTE: This must be a macro (rather than a function with trait bounds)
55+ // because there's no way, in a generic context, to enforce that two types
56+ // have the same size. `core::mem::transmute` uses compiler magic to enforce
57+ // this so long as the types are concrete.
58+ ( #![ allow( shrink) ] $e: expr) => { {
59+ let mut e = $e;
6160 if false {
62- // This branch, though never taken, ensures that the type of `e` is
63- // `IntoBytes` and that the type of this macro invocation expression
64- // is `FromBytes`.
61+ $crate:: __transmute_inner!( @assert_into_bytes_from_bytes e)
62+ } else {
63+ use $crate:: util:: macro_util:: core_reexport:: mem:: ManuallyDrop ;
64+
65+ #[ repr( C ) ]
66+ union Transmute <Src , Dst > {
67+ src: ManuallyDrop <Src >,
68+ dst: ManuallyDrop <Dst >,
69+ }
6570
66- struct AssertIsIntoBytes <T : $crate:: IntoBytes >( T ) ;
67- let _ = AssertIsIntoBytes ( e) ;
71+ // TODO: Update this safety comment.
72+ //
73+ // SAFETY: `core::mem::transmute` ensures that the type of `e` and
74+ // the type of this macro invocation expression have the same size.
75+ // We know this transmute is safe thanks to the `IntoBytes` and
76+ // `FromBytes` bounds enforced by the `false` branch.
77+ let u: Transmute <_, _> = unsafe {
78+ // Clippy: We can't annotate the types; this macro is designed
79+ // to infer the types from the calling context.
80+ #[ allow( clippy:: missing_transmute_annotations, unnecessary_transmutes) ]
81+ $crate:: util:: macro_util:: core_reexport:: mem:: transmute( e)
82+ } ;
6883
69- struct AssertIsFromBytes <U : $crate:: FromBytes >( U ) ;
70- #[ allow( unused, unreachable_code) ]
71- let u = AssertIsFromBytes ( loop { } ) ;
72- u. 0
84+ if false {
85+ // SAFETY: This code is never executed.
86+ e = ManuallyDrop :: into_inner( unsafe { u. src } ) ;
87+ // Suppress the `unused_assignments` lint on the previous line.
88+ let _ = e;
89+ loop { }
90+ } else {
91+ // TODO: Safety comment
92+ let dst = unsafe { u. dst } ;
93+ $crate:: util:: macro_util:: must_use( ManuallyDrop :: into_inner( dst) )
94+ }
95+ }
96+ } } ;
97+ ( $e: expr) => { {
98+ let e = $e;
99+ if false {
100+ $crate:: __transmute_inner!( @assert_into_bytes_from_bytes e)
73101 } else {
74102 // SAFETY: `core::mem::transmute` ensures that the type of `e` and
75103 // the type of this macro invocation expression have the same size.
76104 // We know this transmute is safe thanks to the `IntoBytes` and
77105 // `FromBytes` bounds enforced by the `false` branch.
78- //
79- // We use this reexport of `core::mem::transmute` because we know it
80- // will always be available for crates which are using the 2015
81- // edition of Rust. By contrast, if we were to use
82- // `std::mem::transmute`, this macro would not work for such crates
83- // in `no_std` contexts, and if we were to use
84- // `core::mem::transmute`, this macro would not work in `std`
85- // contexts in which `core` was not manually imported. This is not a
86- // problem for 2018 edition crates.
87106 let u = unsafe {
88107 // Clippy: We can't annotate the types; this macro is designed
89108 // to infer the types from the calling context.
@@ -92,7 +111,29 @@ macro_rules! transmute {
92111 } ;
93112 $crate:: util:: macro_util:: must_use( u)
94113 }
95- } }
114+ } } ;
115+ }
116+
117+ #[ macro_export]
118+ #[ doc( hidden) ]
119+ macro_rules! __transmute_inner {
120+ ( @assert_into_bytes_from_bytes $e: expr) => { {
121+ // This branch, though never taken, ensures that the type of `e` is
122+ // `IntoBytes` and that the type of the outer macro invocation
123+ // expression is `FromBytes`.
124+
125+ fn transmute<Src , Dst >( src: Src ) -> Dst
126+ where
127+ Src : $crate:: IntoBytes ,
128+ Dst : $crate:: FromBytes ,
129+ {
130+ let _ = src;
131+ loop { }
132+ }
133+ loop { }
134+ #[ allow( unreachable_code) ]
135+ transmute( $e)
136+ } } ;
96137}
97138
98139/// Safely transmutes a mutable or immutable reference of one type to an
@@ -1109,6 +1150,10 @@ mod tests {
11091150 let x: [ u8 ; 8 ] = transmute ! ( array_of_arrays) ;
11101151 assert_eq ! ( x, array_of_u8s) ;
11111152
1153+ // Test that memory is transmuted as expected when shrinking.
1154+ let x: [ [ u8 ; 2 ] ; 3 ] = transmute ! ( #![ allow( shrink) ] array_of_u8s) ;
1155+ assert_eq ! ( x, [ [ 0u8 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ] ) ;
1156+
11121157 // Test that the source expression's value is forgotten rather than
11131158 // dropped.
11141159 #[ derive( IntoBytes ) ]
@@ -1121,12 +1166,16 @@ mod tests {
11211166 }
11221167 #[ allow( clippy:: let_unit_value) ]
11231168 let _: ( ) = transmute ! ( PanicOnDrop ( ( ) ) ) ;
1169+ #[ allow( clippy:: let_unit_value) ]
1170+ let _: ( ) = transmute ! ( #![ allow( shrink) ] PanicOnDrop ( ( ) ) ) ;
11241171
11251172 // Test that `transmute!` is legal in a const context.
11261173 const ARRAY_OF_U8S : [ u8 ; 8 ] = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
11271174 const ARRAY_OF_ARRAYS : [ [ u8 ; 2 ] ; 4 ] = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
11281175 const X : [ [ u8 ; 2 ] ; 4 ] = transmute ! ( ARRAY_OF_U8S ) ;
11291176 assert_eq ! ( X , ARRAY_OF_ARRAYS ) ;
1177+ const X_SHRINK : [ [ u8 ; 2 ] ; 3 ] = transmute ! ( #![ allow( shrink) ] ARRAY_OF_U8S ) ;
1178+ assert_eq ! ( X_SHRINK , [ [ 0u8 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ] ) ;
11301179
11311180 // Test that `transmute!` works with `!Immutable` types.
11321181 let x: usize = transmute ! ( UnsafeCell :: new( 1usize ) ) ;
0 commit comments