@@ -182,22 +182,15 @@ 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 ) ;
186
185
struct AssertSrcIsIntoBytes <' a, T : ?:: core:: marker:: Sized + $crate:: IntoBytes >( & ' a T ) ;
187
186
struct AssertSrcIsImmutable <' a, T : ?:: core:: marker:: Sized + $crate:: Immutable >( & ' a T ) ;
188
- struct AssertDstIsSized <' a, T : :: core:: marker:: Sized >( & ' a T ) ;
189
187
struct AssertDstIsFromBytes <' a, U : ?:: core:: marker:: Sized + $crate:: FromBytes >( & ' a U ) ;
190
188
struct AssertDstIsImmutable <' a, T : ?:: core:: marker:: Sized + $crate:: Immutable >( & ' a T ) ;
191
189
192
- let _ = AssertSrcIsSized ( e) ;
193
190
let _ = AssertSrcIsIntoBytes ( e) ;
194
191
let _ = AssertSrcIsImmutable ( e) ;
195
192
196
193
if true {
197
- #[ allow( unused, unreachable_code) ]
198
- let u = AssertDstIsSized ( loop { } ) ;
199
- u. 0
200
- } else if true {
201
194
#[ allow( unused, unreachable_code) ]
202
195
let u = AssertDstIsFromBytes ( loop { } ) ;
203
196
u. 0
@@ -206,36 +199,13 @@ macro_rules! transmute_ref {
206
199
let u = AssertDstIsImmutable ( loop { } ) ;
207
200
u. 0
208
201
}
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
202
} 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)
203
+ use $crate:: util:: macro_util:: TransmuteRefDst ;
204
+ let t = $crate:: util:: macro_util:: Wrap ( e) ;
205
+ // SAFETY: todo
206
+ unsafe {
207
+ t. transmute_ref( )
208
+ }
239
209
}
240
210
} }
241
211
}
@@ -334,26 +304,18 @@ macro_rules! transmute_mut {
334
304
// writing, mutable references are banned), the error message
335
305
// appears to originate in the user's code rather than in the
336
306
// internals of this macro.
337
- struct AssertSrcIsSized <' a, T : :: core:: marker:: Sized >( & ' a T ) ;
338
307
struct AssertSrcIsFromBytes <' a, T : ?:: core:: marker:: Sized + $crate:: FromBytes >( & ' a T ) ;
339
308
struct AssertSrcIsIntoBytes <' a, T : ?:: core:: marker:: Sized + $crate:: IntoBytes >( & ' a T ) ;
340
- struct AssertDstIsSized <' a, T : :: core:: marker:: Sized >( & ' a T ) ;
341
309
struct AssertDstIsFromBytes <' a, T : ?:: core:: marker:: Sized + $crate:: FromBytes >( & ' a T ) ;
342
310
struct AssertDstIsIntoBytes <' a, T : ?:: core:: marker:: Sized + $crate:: IntoBytes >( & ' a T ) ;
343
311
344
312
if true {
345
- let _ = AssertSrcIsSized ( & * e) ;
346
- } else if true {
347
313
let _ = AssertSrcIsFromBytes ( & * e) ;
348
314
} else {
349
315
let _ = AssertSrcIsIntoBytes ( & * e) ;
350
316
}
351
317
352
318
if true {
353
- #[ allow( unused, unreachable_code) ]
354
- let u = AssertDstIsSized ( loop { } ) ;
355
- & mut * u. 0
356
- } else if true {
357
319
#[ allow( unused, unreachable_code) ]
358
320
let u = AssertDstIsFromBytes ( loop { } ) ;
359
321
& mut * u. 0
@@ -362,32 +324,13 @@ macro_rules! transmute_mut {
362
324
let u = AssertDstIsIntoBytes ( loop { } ) ;
363
325
& mut * u. 0
364
326
}
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
327
} 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)
328
+ use $crate:: util:: macro_util:: TransmuteMutDst ;
329
+ let t = $crate:: util:: macro_util:: Wrap ( e) ;
330
+ // SAFETY: todo
331
+ unsafe {
332
+ t. transmute_mut( )
333
+ }
391
334
}
392
335
} }
393
336
}
@@ -1038,6 +981,18 @@ mod tests {
1038
981
assert_eq ! ( x. into_inner( ) , 1 ) ;
1039
982
}
1040
983
984
+ // A `Sized` type which doesn't implement `KnownLayout` (it is "not
985
+ // `KnownLayout`", or `Nkl`).
986
+ //
987
+ // This permits us to test that `transmute_ref!` and `transmute_mut!` work
988
+ // for types which are `Sized + !KnownLayout`. When we added support for
989
+ // slice DSTs in #1924, this new support relied on `KnownLayout`, but we
990
+ // need to make sure to remain backwards-compatible with code which ueses
991
+ // these macros with types which are `!KnownLayout`.
992
+ #[ derive( FromBytes , IntoBytes , Immutable , PartialEq , Eq , Debug ) ]
993
+ #[ repr( transparent) ]
994
+ struct Nkl < T > ( T ) ;
995
+
1041
996
#[ test]
1042
997
fn test_transmute_ref ( ) {
1043
998
// Test that memory is transmuted as expected.
@@ -1055,6 +1010,39 @@ mod tests {
1055
1010
const X : & ' static [ [ u8 ; 2 ] ; 4 ] = transmute_ref ! ( & ARRAY_OF_U8S ) ;
1056
1011
assert_eq ! ( * X , ARRAY_OF_ARRAYS ) ;
1057
1012
1013
+ // Call through a generic function to make sure our autoref
1014
+ // specialization trick works even when types are generic.
1015
+ const fn transmute_ref < T , U > ( t : & T ) -> & U
1016
+ where
1017
+ T : IntoBytes + Immutable ,
1018
+ U : FromBytes + Immutable ,
1019
+ {
1020
+ transmute_ref ! ( t)
1021
+ }
1022
+
1023
+ // Test that `transmute_ref!` supports non-`KnownLayout` `Sized` types.
1024
+ const ARRAY_OF_NKL_U8S : Nkl < [ u8 ; 8 ] > = Nkl ( [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ) ;
1025
+ const ARRAY_OF_NKL_ARRAYS : Nkl < [ [ u8 ; 2 ] ; 4 ] > = Nkl ( [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ) ;
1026
+ const X_NKL : & Nkl < [ [ u8 ; 2 ] ; 4 ] > = transmute_ref ( & ARRAY_OF_NKL_U8S ) ;
1027
+ assert_eq ! ( * X_NKL , ARRAY_OF_NKL_ARRAYS ) ;
1028
+
1029
+ // Test that `transmute_ref!` works on slice DSTs in and that memory is
1030
+ // transmuted as expected.
1031
+ #[ derive( KnownLayout , Immutable , FromBytes , IntoBytes , PartialEq , Debug ) ]
1032
+ #[ repr( C ) ]
1033
+ struct SliceDst < T > {
1034
+ a : u8 ,
1035
+ b : [ T ] ,
1036
+ }
1037
+
1038
+ use crate :: byteorder:: native_endian:: U16 ;
1039
+ let slice_dst_of_u8s =
1040
+ SliceDst :: < [ u8 ; 2 ] > :: ref_from_bytes ( & [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] [ ..] ) . unwrap ( ) ;
1041
+ let slice_dst_of_u16s =
1042
+ SliceDst :: < U16 > :: ref_from_bytes ( & [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] [ ..] ) . unwrap ( ) ;
1043
+ let x: & SliceDst < U16 > = transmute_ref ! ( slice_dst_of_u8s) ;
1044
+ assert_eq ! ( x, slice_dst_of_u16s) ;
1045
+
1058
1046
// Test that it's legal to transmute a reference while shrinking the
1059
1047
// lifetime (note that `X` has the lifetime `'static`).
1060
1048
let x: & [ u8 ; 8 ] = transmute_ref ! ( X ) ;
@@ -1198,6 +1186,15 @@ mod tests {
1198
1186
let x: & mut [ u8 ; 8 ] = transmute_mut ! ( & mut array_of_arrays) ;
1199
1187
assert_eq ! ( * x, array_of_u8s) ;
1200
1188
}
1189
+
1190
+ // Test that `transmute_mut!` supports non-`KnownLayout` types.
1191
+ let mut array_of_u8s = Nkl ( [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ) ;
1192
+ let mut array_of_arrays = Nkl ( [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ) ;
1193
+ let x: & mut Nkl < [ [ u8 ; 2 ] ; 4 ] > = transmute_mut ! ( & mut array_of_u8s) ;
1194
+ assert_eq ! ( * x, array_of_arrays) ;
1195
+ let x: & mut Nkl < [ u8 ; 8 ] > = transmute_mut ! ( & mut array_of_arrays) ;
1196
+ assert_eq ! ( * x, array_of_u8s) ;
1197
+
1201
1198
// Test that `transmute_mut!` supports decreasing alignment.
1202
1199
let mut u = AU64 ( 0 ) ;
1203
1200
let array = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
@@ -1209,6 +1206,30 @@ mod tests {
1209
1206
#[ allow( clippy:: useless_transmute) ]
1210
1207
let y: & u8 = transmute_mut ! ( & mut x) ;
1211
1208
assert_eq ! ( * y, 0 ) ;
1209
+
1210
+ // Test that `transmute_mut!` works on slice DSTs in and that memory is
1211
+ // transmuted as expected.
1212
+ #[ derive( KnownLayout , Immutable , FromBytes , IntoBytes , PartialEq , Debug ) ]
1213
+ #[ repr( C ) ]
1214
+ struct SliceDst < T > {
1215
+ a : u8 ,
1216
+ b : [ T ] ,
1217
+ }
1218
+
1219
+ use crate :: byteorder:: native_endian:: U16 ;
1220
+ let mut bytes = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] ;
1221
+ let slice_dst_of_u8s = SliceDst :: < [ u8 ; 2 ] > :: mut_from_bytes ( & mut bytes[ ..] ) . unwrap ( ) ;
1222
+ let mut bytes = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] ;
1223
+ let slice_dst_of_u16s = SliceDst :: < U16 > :: mut_from_bytes ( & mut bytes[ ..] ) . unwrap ( ) ;
1224
+ let x: & mut SliceDst < U16 > = transmute_mut ! ( slice_dst_of_u8s) ;
1225
+ assert_eq ! ( x, slice_dst_of_u16s) ;
1226
+
1227
+ // Test that `transmute_mut!` works on slices that memory is transmuted
1228
+ // as expected.
1229
+ let array_of_u16s: & mut [ u16 ] = & mut [ 0u16 , 1 , 2 ] ;
1230
+ let array_of_i16s: & mut [ i16 ] = & mut [ 0i16 , 1 , 2 ] ;
1231
+ let x: & mut [ i16 ] = transmute_mut ! ( array_of_u16s) ;
1232
+ assert_eq ! ( x, array_of_i16s) ;
1212
1233
}
1213
1234
1214
1235
#[ test]
0 commit comments