@@ -182,22 +182,23 @@ macro_rules! transmute_ref {
182
182
// this macro expression is `&U` where `U: 'u + Sized + FromBytes +
183
183
// Immutable`, and that `'t` outlives `'u`.
184
184
185
- struct AssertSrcIsSized <' a, T : :: core:: marker:: Sized >( & ' a T ) ;
185
+ // struct AssertSrcIsSized<'a, T: ::core::marker::Sized>(&'a T);
186
186
struct AssertSrcIsIntoBytes <' a, T : ?:: core:: marker:: Sized + $crate:: IntoBytes >( & ' a T ) ;
187
187
struct AssertSrcIsImmutable <' a, T : ?:: core:: marker:: Sized + $crate:: Immutable >( & ' a T ) ;
188
- struct AssertDstIsSized <' a, T : :: core:: marker:: Sized >( & ' a T ) ;
188
+ // struct AssertDstIsSized<'a, T: ::core::marker::Sized>(&'a T);
189
189
struct AssertDstIsFromBytes <' a, U : ?:: core:: marker:: Sized + $crate:: FromBytes >( & ' a U ) ;
190
190
struct AssertDstIsImmutable <' a, T : ?:: core:: marker:: Sized + $crate:: Immutable >( & ' a T ) ;
191
191
192
- let _ = AssertSrcIsSized ( e) ;
192
+ // let _ = AssertSrcIsSized(e);
193
193
let _ = AssertSrcIsIntoBytes ( e) ;
194
194
let _ = AssertSrcIsImmutable ( e) ;
195
195
196
+ // if true {
197
+ // #[allow(unused, unreachable_code)]
198
+ // let u = AssertDstIsSized(loop {});
199
+ // u.0
200
+ // } else
196
201
if true {
197
- #[ allow( unused, unreachable_code) ]
198
- let u = AssertDstIsSized ( loop { } ) ;
199
- u. 0
200
- } else if true {
201
202
#[ allow( unused, unreachable_code) ]
202
203
let u = AssertDstIsFromBytes ( loop { } ) ;
203
204
u. 0
@@ -206,36 +207,20 @@ macro_rules! transmute_ref {
206
207
let u = AssertDstIsImmutable ( loop { } ) ;
207
208
u. 0
208
209
}
209
- } else if false {
210
- // This branch, though never taken, ensures that `size_of::<T>() ==
211
- // size_of::<U>()` and that that `align_of::<T>() >=
212
- // align_of::<U>()`.
213
-
214
- // `t` is inferred to have type `T` because it's assigned to `e` (of
215
- // type `&T`) as `&t`.
216
- let mut t = loop { } ;
217
- e = & t;
218
-
219
- // `u` is inferred to have type `U` because it's used as `&u` as the
220
- // value returned from this branch.
221
- let u;
222
-
223
- $crate:: assert_size_eq!( t, u) ;
224
- $crate:: assert_align_gt_eq!( t, u) ;
225
-
226
- & u
227
210
} else {
228
- // SAFETY: For source type `Src` and destination type `Dst`:
229
- // - We know that `Src: IntoBytes + Immutable` and `Dst: FromBytes +
230
- // Immutable` thanks to the uses of `AssertSrcIsIntoBytes`,
231
- // `AssertSrcIsImmutable`, `AssertDstIsFromBytes`, and
232
- // `AssertDstIsImmutable` above.
233
- // - We know that `size_of::<Src>() == size_of::<Dst>()` thanks to
234
- // the use of `assert_size_eq!` above.
235
- // - We know that `align_of::<Src>() >= align_of::<Dst>()` thanks to
236
- // the use of `assert_align_gt_eq!` above.
237
- let u = unsafe { $crate:: util:: macro_util:: transmute_ref( e) } ;
238
- $crate:: util:: macro_util:: must_use( u)
211
+ let opt = $crate:: util:: macro_util:: static_assert_transmute_ref( & * e) ;
212
+ if let Some ( u) = opt {
213
+ loop { }
214
+ & * u
215
+ } else {
216
+ let e: * const _ = e;
217
+ #[ allow( clippy:: as_conversions) ]
218
+ let u = e as * const _;
219
+ // SAFETY: TODO (needs to be valid for both older and newer toolchains).
220
+ #[ allow( clippy:: as_conversions) ]
221
+ let u = unsafe { & * u } ;
222
+ $crate:: util:: macro_util:: must_use( u)
223
+ }
239
224
}
240
225
} }
241
226
}
@@ -334,26 +319,27 @@ macro_rules! transmute_mut {
334
319
// writing, mutable references are banned), the error message
335
320
// appears to originate in the user's code rather than in the
336
321
// internals of this macro.
337
- struct AssertSrcIsSized <' a, T : :: core:: marker:: Sized >( & ' a T ) ;
322
+ // struct AssertSrcIsSized<'a, T: ::core::marker::Sized>(&'a T);
338
323
struct AssertSrcIsFromBytes <' a, T : ?:: core:: marker:: Sized + $crate:: FromBytes >( & ' a T ) ;
339
324
struct AssertSrcIsIntoBytes <' a, T : ?:: core:: marker:: Sized + $crate:: IntoBytes >( & ' a T ) ;
340
- struct AssertDstIsSized <' a, T : :: core:: marker:: Sized >( & ' a T ) ;
325
+ // struct AssertDstIsSized<'a, T: ::core::marker::Sized>(&'a T);
341
326
struct AssertDstIsFromBytes <' a, T : ?:: core:: marker:: Sized + $crate:: FromBytes >( & ' a T ) ;
342
327
struct AssertDstIsIntoBytes <' a, T : ?:: core:: marker:: Sized + $crate:: IntoBytes >( & ' a T ) ;
343
328
344
329
if true {
345
- let _ = AssertSrcIsSized ( & * e) ;
330
+ // let _ = AssertSrcIsSized(&*e);
346
331
} else if true {
347
332
let _ = AssertSrcIsFromBytes ( & * e) ;
348
333
} else {
349
334
let _ = AssertSrcIsIntoBytes ( & * e) ;
350
335
}
351
336
337
+ // if true {
338
+ // #[allow(unused, unreachable_code)]
339
+ // let u = AssertDstIsSized(loop {});
340
+ // &mut *u.0
341
+ // } else
352
342
if true {
353
- #[ allow( unused, unreachable_code) ]
354
- let u = AssertDstIsSized ( loop { } ) ;
355
- & mut * u. 0
356
- } else if true {
357
343
#[ allow( unused, unreachable_code) ]
358
344
let u = AssertDstIsFromBytes ( loop { } ) ;
359
345
& mut * u. 0
@@ -362,32 +348,20 @@ macro_rules! transmute_mut {
362
348
let u = AssertDstIsIntoBytes ( loop { } ) ;
363
349
& mut * u. 0
364
350
}
365
- } else if false {
366
- // This branch, though never taken, ensures that `size_of::<T>() ==
367
- // size_of::<U>()` and that that `align_of::<T>() >=
368
- // align_of::<U>()`.
369
-
370
- // `t` is inferred to have type `T` because it's assigned to `e` (of
371
- // type `&mut T`) as `&mut t`.
372
- let mut t = loop { } ;
373
- e = & mut t;
374
-
375
- // `u` is inferred to have type `U` because it's used as `&mut u` as
376
- // the value returned from this branch.
377
- let u;
378
-
379
- $crate:: assert_size_eq!( t, u) ;
380
- $crate:: assert_align_gt_eq!( t, u) ;
381
-
382
- & mut u
383
351
} else {
384
- // SAFETY: For source type `Src` and destination type `Dst`:
385
- // - We know that `size_of::<Src>() == size_of::<Dst>()` thanks to
386
- // the use of `assert_size_eq!` above.
387
- // - We know that `align_of::<Src>() >= align_of::<Dst>()` thanks to
388
- // the use of `assert_align_gt_eq!` above.
389
- let u = unsafe { $crate:: util:: macro_util:: transmute_mut( e) } ;
390
- $crate:: util:: macro_util:: must_use( u)
352
+ let opt = $crate:: util:: macro_util:: static_assert_transmute_ref( & * e) ;
353
+ if let Some ( u) = opt {
354
+ loop { }
355
+ & mut * u
356
+ } else {
357
+ let e: * mut _ = e;
358
+ #[ allow( clippy:: as_conversions) ]
359
+ let u = e as * mut _;
360
+ // SAFETY: TODO (needs to be valid for both older and newer toolchains).
361
+ #[ allow( clippy:: as_conversions) ]
362
+ let u = unsafe { & mut * u } ;
363
+ $crate:: util:: macro_util:: must_use( u)
364
+ }
391
365
}
392
366
} }
393
367
}
@@ -793,6 +767,37 @@ mod tests {
793
767
const X : & ' static [ [ u8 ; 2 ] ; 4 ] = transmute_ref ! ( & ARRAY_OF_U8S ) ;
794
768
assert_eq ! ( * X , ARRAY_OF_ARRAYS ) ;
795
769
770
+ // Test that `transmute_ref!` works on slice DSTs in and that memory is
771
+ // transmuted as expected.
772
+ #[ derive( KnownLayout , Immutable , FromBytes , IntoBytes , PartialEq , Debug ) ]
773
+ #[ repr( C ) ]
774
+ struct SliceDst < T > {
775
+ a : u8 ,
776
+ b : [ T ] ,
777
+ }
778
+
779
+ use crate :: byteorder:: native_endian:: U16 ;
780
+ let slice_dst_of_u8s =
781
+ SliceDst :: < [ u8 ; 2 ] > :: ref_from_bytes ( & [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] [ ..] ) . unwrap ( ) ;
782
+ let slice_dst_of_u16s =
783
+ SliceDst :: < U16 > :: ref_from_bytes ( & [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] [ ..] ) . unwrap ( ) ;
784
+ let x: & SliceDst < U16 > = transmute_ref ! ( slice_dst_of_u8s) ;
785
+ assert_eq ! ( x, slice_dst_of_u16s) ;
786
+
787
+ // Test that `transmute_ref!` works on slices in a const context and
788
+ // that memory is transmuted as expected.
789
+ const ARRAY_OF_U16S : & [ u16 ] = & [ 0u16 , 1 , 2 ] ;
790
+ const ARRAY_OF_I16S : & [ i16 ] = & [ 0i16 , 1 , 2 ] ;
791
+ const Y : & [ i16 ] = transmute_ref ! ( ARRAY_OF_U16S ) ;
792
+ assert_eq ! ( Y , ARRAY_OF_I16S ) ;
793
+
794
+ // Test that `transmute_ref!` works on slice DSTs in a const context. We
795
+ // have no way of synthesizing slice DST values in a const context, so
796
+ // this just tests that it compiles.
797
+ const fn _transmute_slice_dst_ref ( from : & SliceDst < [ u8 ; 2 ] > ) -> & SliceDst < U16 > {
798
+ transmute_ref ! ( from)
799
+ }
800
+
796
801
// Test that it's legal to transmute a reference while shrinking the
797
802
// lifetime (note that `X` has the lifetime `'static`).
798
803
let x: & [ u8 ; 8 ] = transmute_ref ! ( X ) ;
@@ -947,6 +952,30 @@ mod tests {
947
952
#[ allow( clippy:: useless_transmute) ]
948
953
let y: & u8 = transmute_mut ! ( & mut x) ;
949
954
assert_eq ! ( * y, 0 ) ;
955
+
956
+ // Test that `transmute_mut!` works on slice DSTs in and that memory is
957
+ // transmuted as expected.
958
+ #[ derive( KnownLayout , Immutable , FromBytes , IntoBytes , PartialEq , Debug ) ]
959
+ #[ repr( C ) ]
960
+ struct SliceDst < T > {
961
+ a : u8 ,
962
+ b : [ T ] ,
963
+ }
964
+
965
+ use crate :: byteorder:: native_endian:: U16 ;
966
+ let mut bytes = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] ;
967
+ let slice_dst_of_u8s = SliceDst :: < [ u8 ; 2 ] > :: mut_from_bytes ( & mut bytes[ ..] ) . unwrap ( ) ;
968
+ let mut bytes = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] ;
969
+ let slice_dst_of_u16s = SliceDst :: < U16 > :: mut_from_bytes ( & mut bytes[ ..] ) . unwrap ( ) ;
970
+ let x: & mut SliceDst < U16 > = transmute_mut ! ( slice_dst_of_u8s) ;
971
+ assert_eq ! ( x, slice_dst_of_u16s) ;
972
+
973
+ // Test that `transmute_mut!` works on slices that memory is transmuted
974
+ // as expected.
975
+ let array_of_u16s: & mut [ u16 ] = & mut [ 0u16 , 1 , 2 ] ;
976
+ let array_of_i16s: & mut [ i16 ] = & mut [ 0i16 , 1 , 2 ] ;
977
+ let x: & mut [ i16 ] = transmute_mut ! ( array_of_u16s) ;
978
+ assert_eq ! ( x, array_of_i16s) ;
950
979
}
951
980
952
981
#[ test]
0 commit comments