@@ -184,6 +184,8 @@ macro_rules! transmute {
184184 } } ;
185185}
186186
187+ // TODO: Update these docs to mention sized -> unsized.
188+
187189/// Safely transmutes a mutable or immutable reference of one type to an
188190/// immutable reference of another type of the same size and compatible
189191/// alignment.
@@ -351,13 +353,35 @@ macro_rules! transmute_ref {
351353 // SAFETY: The `if false` branch ensures that:
352354 // - `Src: IntoBytes + Immutable`
353355 // - `Dst: FromBytes + Immutable`
354- unsafe {
355- t. transmute_ref( )
356+ if false {
357+ // This branch exists solely to force the compiler to infer the
358+ // type of `Dst` *before* it attempts to resolve the method call
359+ // to `transmute_ref` in the `else` branch.
360+ //
361+ // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
362+ // compiler will eagerly select the inherent impl of
363+ // `transmute_ref` (which requires `Dst: Sized`) because inherent
364+ // methods take priority over trait methods. It does this before
365+ // it realizes `Dst` is `!Sized`, leading to a compile error when
366+ // it checks the bounds later.
367+ //
368+ // By calling this helper (which returns `&Dst`), we force `Dst`
369+ // to be fully resolved. By the time it gets to the `else`
370+ // branch, the compiler knows `Dst` is `!Sized`, properly
371+ // disqualifies the inherent method, and falls back to the trait
372+ // implementation.
373+ t. transmute_ref_inference_helper( )
374+ } else {
375+ unsafe {
376+ t. transmute_ref( )
377+ }
356378 }
357379 }
358380 } }
359381}
360382
383+ // TODO: Update these docs to mention sized -> unsized.
384+
361385/// Safely transmutes a mutable reference of one type to a mutable reference of
362386/// another type of the same size and compatible alignment.
363387///
@@ -503,7 +527,26 @@ macro_rules! transmute_mut {
503527 #[ allow( unused) ]
504528 use $crate:: util:: macro_util:: TransmuteMutDst as _;
505529 let t = $crate:: util:: macro_util:: Wrap :: new( e) ;
506- t. transmute_mut( )
530+ if false {
531+ // This branch exists solely to force the compiler to infer the type
532+ // of `Dst` *before* it attempts to resolve the method call to
533+ // `transmute_mut` in the `else` branch.
534+ //
535+ // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
536+ // compiler will eagerly select the inherent impl of `transmute_mut`
537+ // (which requires `Dst: Sized`) because inherent methods take
538+ // priority over trait methods. It does this before it realizes
539+ // `Dst` is `!Sized`, leading to a compile error when it checks the
540+ // bounds later.
541+ //
542+ // By calling this helper (which returns `&mut Dst`), we force `Dst`
543+ // to be fully resolved. By the time it gets to the `else` branch,
544+ // the compiler knows `Dst` is `!Sized`, properly disqualifies the
545+ // inherent method, and falls back to the trait implementation.
546+ t. transmute_mut_inference_helper( )
547+ } else {
548+ t. transmute_mut( )
549+ }
507550 } }
508551}
509552
@@ -1241,6 +1284,13 @@ mod tests {
12411284 const X : & ' static [ [ u8 ; 2 ] ; 4 ] = transmute_ref ! ( & ARRAY_OF_U8S ) ;
12421285 assert_eq ! ( * X , ARRAY_OF_ARRAYS ) ;
12431286
1287+ // Test sized -> unsized transmutation.
1288+ let array_of_u8s = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
1289+ let array_of_arrays = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
1290+ let slice_of_arrays = & array_of_arrays[ ..] ;
1291+ let x: & [ [ u8 ; 2 ] ] = transmute_ref ! ( & array_of_u8s) ;
1292+ assert_eq ! ( x, slice_of_arrays) ;
1293+
12441294 // Before 1.61.0, we can't define the `const fn transmute_ref` function
12451295 // that we do on and after 1.61.0.
12461296 #[ cfg( no_zerocopy_generic_bounds_in_const_fn_1_61_0) ]
@@ -1532,6 +1582,13 @@ mod tests {
15321582 let slice_dst_small = SliceDst :: < U16 , u8 > :: mut_from_bytes ( & mut bytes[ ..] ) . unwrap ( ) ;
15331583 let x: & mut SliceDst < U16 , u8 > = transmute_mut ! ( slice_dst_big) ;
15341584 assert_eq ! ( x, slice_dst_small) ;
1585+
1586+ // Test sized -> unsized transmutation.
1587+ let mut array_of_u8s = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
1588+ let mut array_of_arrays = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
1589+ let slice_of_arrays = & mut array_of_arrays[ ..] ;
1590+ let x: & mut [ [ u8 ; 2 ] ] = transmute_mut ! ( & mut array_of_u8s) ;
1591+ assert_eq ! ( x, slice_of_arrays) ;
15351592 }
15361593
15371594 #[ test]
0 commit comments