@@ -38,29 +38,61 @@ const TAG_N: usize = 0b1101;
38
38
const TAG_O : usize = 0b1110 ;
39
39
const TAG_P : usize = 0b1111 ;
40
40
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
+
41
73
#[ inline( always) ]
42
74
fn check_tag ( ptr : ErasedPtr , mask : usize , tag : usize ) -> bool {
43
75
debug_assert_eq ! ( tag & mask, tag) ;
44
- ( ptr. as_ptr ( ) as usize & mask) == tag
76
+ ptr_addr ( ptr_mask ( ptr. as_ptr ( ) , mask) ) == tag
45
77
}
46
78
47
79
#[ inline( always) ]
48
80
fn set_tag ( ptr : ErasedPtr , mask : usize , tag : usize ) -> ErasedPtr {
49
81
debug_assert_eq ! ( tag & mask, tag) ;
50
82
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) ) }
52
84
}
53
85
54
86
#[ inline( always) ]
55
87
fn unset_tag ( ptr : ErasedPtr , mask : usize , tag : usize ) -> ErasedPtr {
56
88
debug_assert_eq ! ( tag & mask, tag) ;
57
89
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) ) }
59
91
}
60
92
61
93
#[ inline( always) ]
62
94
fn 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) ) }
64
96
}
65
97
66
98
#[ cfg( has_never) ]
0 commit comments