@@ -38,29 +38,61 @@ const TAG_N: usize = 0b1101;
3838const TAG_O : usize = 0b1110 ;
3939const TAG_P : usize = 0b1111 ;
4040
41+ // See rust-lang/rust#95228 for why these are necessary.
42+ fn ptr_addr < T > ( this : * mut T ) -> usize {
43+ // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
44+ this as usize
45+ }
46+
47+ fn ptr_with_addr < T > ( this : * mut T , addr : usize ) -> * mut T {
48+ // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
49+ //
50+ // In the mean-time, this operation is defined to be "as if" it was
51+ // a wrapping_offset, so we can emulate it as such. This should properly
52+ // restore pointer provenance even under today's compiler.
53+ let this_addr = ptr_addr ( this) as isize ;
54+ let dest_addr = addr as isize ;
55+ let offset = dest_addr. wrapping_sub ( this_addr) ;
56+
57+ // This is the canonical desugarring of this operation
58+ this. cast :: < u8 > ( ) . wrapping_offset ( offset) . cast :: < T > ( )
59+ }
60+
61+ fn ptr_map_addr < T > ( this : * mut T , f : impl FnOnce ( usize ) -> usize ) -> * mut T {
62+ ptr_with_addr ( this, f ( ptr_addr ( this) ) )
63+ }
64+
65+ fn ptr_tag < T > ( this : * mut T , tag : usize ) -> * mut T {
66+ ptr_map_addr ( this, |addr| addr | tag)
67+ }
68+
69+ fn ptr_mask < T > ( this : * mut T , mask : usize ) -> * mut T {
70+ ptr_map_addr ( this, |addr| addr & mask)
71+ }
72+
4173#[ inline( always) ]
4274fn check_tag ( ptr : ErasedPtr , mask : usize , tag : usize ) -> bool {
4375 debug_assert_eq ! ( tag & mask, tag) ;
44- ( ptr. as_ptr ( ) as usize & mask) == tag
76+ ptr_addr ( ptr_mask ( ptr. as_ptr ( ) , mask) ) == tag
4577}
4678
4779#[ inline( always) ]
4880fn set_tag ( ptr : ErasedPtr , mask : usize , tag : usize ) -> ErasedPtr {
4981 debug_assert_eq ! ( tag & mask, tag) ;
5082 debug_assert ! ( check_tag( ptr, mask, 0 ) ) ;
51- unsafe { ErasedPtr :: new_unchecked ( ( ptr. as_ptr ( ) as usize | tag) as * mut _ ) }
83+ unsafe { ErasedPtr :: new_unchecked ( ptr_tag ( ptr. as_ptr ( ) , tag) ) }
5284}
5385
5486#[ inline( always) ]
5587fn unset_tag ( ptr : ErasedPtr , mask : usize , tag : usize ) -> ErasedPtr {
5688 debug_assert_eq ! ( tag & mask, tag) ;
5789 debug_assert ! ( check_tag( ptr, mask, tag) ) ;
58- unsafe { ErasedPtr :: new_unchecked ( ( ptr. as_ptr ( ) as usize & !mask) as * mut _ ) }
90+ unsafe { ErasedPtr :: new_unchecked ( ptr_mask ( ptr. as_ptr ( ) , !mask) ) }
5991}
6092
6193#[ inline( always) ]
6294fn unset_any_tag ( ptr : ErasedPtr , mask : usize ) -> ErasedPtr {
63- unsafe { ErasedPtr :: new_unchecked ( ( ptr. as_ptr ( ) as usize & !mask) as * mut _ ) }
95+ unsafe { ErasedPtr :: new_unchecked ( ptr_mask ( ptr. as_ptr ( ) , !mask) ) }
6496}
6597
6698#[ cfg( has_never) ]
0 commit comments