rustc_middle/mir/interpret/
pointer.rs1use std::fmt;
2use std::num::NonZero;
3
4use rustc_abi::{HasDataLayout, Size};
5use rustc_data_structures::static_assert_size;
6use rustc_macros::{HashStable, TyDecodable, TyEncodable};
7
8use super::AllocId;
9
10pub trait PointerArithmetic: HasDataLayout {
15 #[inline(always)]
18 fn pointer_size(&self) -> Size {
19 self.data_layout().pointer_size()
20 }
21
22 #[inline(always)]
23 fn max_size_of_val(&self) -> Size {
24 Size::from_bytes(self.target_isize_max())
25 }
26
27 #[inline]
28 fn target_usize_max(&self) -> u64 {
29 self.pointer_size().unsigned_int_max().try_into().unwrap()
30 }
31
32 #[inline]
33 fn target_isize_min(&self) -> i64 {
34 self.pointer_size().signed_int_min().try_into().unwrap()
35 }
36
37 #[inline]
38 fn target_isize_max(&self) -> i64 {
39 self.pointer_size().signed_int_max().try_into().unwrap()
40 }
41
42 #[inline]
43 fn truncate_to_target_usize(&self, val: u64) -> u64 {
44 self.pointer_size().truncate(val.into()).try_into().unwrap()
45 }
46
47 #[inline]
48 fn sign_extend_to_target_isize(&self, val: u64) -> i64 {
49 self.pointer_size().sign_extend(val.into()).try_into().unwrap()
50 }
51}
52
53impl<T: HasDataLayout> PointerArithmetic for T {}
54
55pub trait Provenance: Copy + PartialEq + fmt::Debug + 'static {
60 const OFFSET_IS_ADDR: bool;
68
69 const WILDCARD: Option<Self>;
71
72 fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
74
75 fn get_alloc_id(self) -> Option<AllocId>;
80}
81
82#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
91pub struct CtfeProvenance(NonZero<u64>);
92
93impl From<AllocId> for CtfeProvenance {
94 fn from(value: AllocId) -> Self {
95 let prov = CtfeProvenance(value.0);
96 assert!(
97 prov.alloc_id() == value,
98 "`AllocId` with the highest bits set cannot be used in CTFE"
99 );
100 prov
101 }
102}
103
104impl fmt::Debug for CtfeProvenance {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 fmt::Debug::fmt(&self.alloc_id(), f)?; if self.immutable() {
108 write!(f, "<imm>")?;
109 }
110 Ok(())
111 }
112}
113
114const IMMUTABLE_MASK: u64 = 1 << 63; const SHARED_REF_MASK: u64 = 1 << 62;
116const ALLOC_ID_MASK: u64 = u64::MAX & !IMMUTABLE_MASK & !SHARED_REF_MASK;
117
118impl CtfeProvenance {
119 #[inline(always)]
121 pub fn alloc_id(self) -> AllocId {
122 AllocId(NonZero::new(self.0.get() & ALLOC_ID_MASK).unwrap())
123 }
124
125 #[inline]
127 pub fn immutable(self) -> bool {
128 self.0.get() & IMMUTABLE_MASK != 0
129 }
130
131 #[inline]
133 pub fn shared_ref(self) -> bool {
134 self.0.get() & SHARED_REF_MASK != 0
135 }
136
137 pub fn into_parts(self) -> (AllocId, bool, bool) {
138 (self.alloc_id(), self.immutable(), self.shared_ref())
139 }
140
141 pub fn from_parts((alloc_id, immutable, shared_ref): (AllocId, bool, bool)) -> Self {
142 let prov = CtfeProvenance::from(alloc_id);
143 if immutable {
144 prov.as_immutable()
146 } else if shared_ref {
147 prov.as_shared_ref()
148 } else {
149 prov
150 }
151 }
152
153 #[inline]
155 pub fn as_immutable(self) -> Self {
156 CtfeProvenance(self.0 | IMMUTABLE_MASK | SHARED_REF_MASK)
157 }
158
159 #[inline]
161 pub fn as_shared_ref(self) -> Self {
162 CtfeProvenance(self.0 | SHARED_REF_MASK)
163 }
164}
165
166impl Provenance for CtfeProvenance {
167 const OFFSET_IS_ADDR: bool = false;
170
171 const WILDCARD: Option<Self> = None;
173
174 fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 fmt::Debug::fmt(&ptr.provenance.alloc_id(), f)?; if ptr.offset.bytes() > 0 {
179 write!(f, "+{:#x}", ptr.offset.bytes())?;
180 }
181 if ptr.provenance.immutable() {
183 write!(f, "<imm>")?;
184 }
185 Ok(())
186 }
187
188 fn get_alloc_id(self) -> Option<AllocId> {
189 Some(self.alloc_id())
190 }
191}
192
193impl Provenance for AllocId {
195 const OFFSET_IS_ADDR: bool = false;
198
199 const WILDCARD: Option<Self> = None;
201
202 fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 if f.alternate() {
205 write!(f, "{:#?}", ptr.provenance)?;
206 } else {
207 write!(f, "{:?}", ptr.provenance)?;
208 }
209 if ptr.offset.bytes() > 0 {
211 write!(f, "+{:#x}", ptr.offset.bytes())?;
212 }
213 Ok(())
214 }
215
216 fn get_alloc_id(self) -> Option<AllocId> {
217 Some(self)
218 }
219}
220
221#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable, Hash)]
225#[derive(HashStable)]
226pub struct Pointer<Prov = CtfeProvenance> {
227 pub(super) offset: Size, pub provenance: Prov,
229}
230
231static_assert_size!(Pointer, 16);
232static_assert_size!(Pointer<Option<CtfeProvenance>>, 16);
235
236impl<Prov: Provenance> fmt::Debug for Pointer<Prov> {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 Provenance::fmt(self, f)
241 }
242}
243
244impl<Prov: Provenance> fmt::Debug for Pointer<Option<Prov>> {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 match self.provenance {
247 Some(prov) => Provenance::fmt(&Pointer::new(prov, self.offset), f),
248 None => write!(f, "{:#x}[noalloc]", self.offset.bytes()),
249 }
250 }
251}
252
253impl<Prov: Provenance> fmt::Display for Pointer<Option<Prov>> {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 if self.provenance.is_none() && self.offset.bytes() == 0 {
256 write!(f, "null pointer")
257 } else {
258 fmt::Debug::fmt(self, f)
259 }
260 }
261}
262
263impl From<AllocId> for Pointer {
265 #[inline(always)]
266 fn from(alloc_id: AllocId) -> Self {
267 Pointer::new(alloc_id.into(), Size::ZERO)
268 }
269}
270impl From<CtfeProvenance> for Pointer {
271 #[inline(always)]
272 fn from(prov: CtfeProvenance) -> Self {
273 Pointer::new(prov, Size::ZERO)
274 }
275}
276
277impl<Prov> From<Pointer<Prov>> for Pointer<Option<Prov>> {
278 #[inline(always)]
279 fn from(ptr: Pointer<Prov>) -> Self {
280 let (prov, offset) = ptr.into_raw_parts();
281 Pointer::new(Some(prov), offset)
282 }
283}
284
285impl<Prov> Pointer<Option<Prov>> {
286 pub fn into_pointer_or_addr(self) -> Result<Pointer<Prov>, Size> {
291 match self.provenance {
292 Some(prov) => Ok(Pointer::new(prov, self.offset)),
293 None => Err(self.offset),
294 }
295 }
296
297 pub fn addr(self) -> Size
300 where
301 Prov: Provenance,
302 {
303 assert!(Prov::OFFSET_IS_ADDR);
304 self.offset
305 }
306
307 #[inline(always)]
310 pub fn without_provenance(addr: u64) -> Self {
311 Pointer { provenance: None, offset: Size::from_bytes(addr) }
312 }
313
314 #[inline(always)]
315 pub fn null() -> Self {
316 Pointer::without_provenance(0)
317 }
318}
319
320impl<Prov> Pointer<Prov> {
321 #[inline(always)]
322 pub fn new(provenance: Prov, offset: Size) -> Self {
323 Pointer { provenance, offset }
324 }
325
326 #[inline(always)]
330 pub fn into_raw_parts(self) -> (Prov, Size) {
331 (self.provenance, self.offset)
332 }
333
334 pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self {
335 Pointer { provenance: f(self.provenance), ..self }
336 }
337
338 #[inline(always)]
339 pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
340 let res =
341 cx.data_layout().truncate_to_target_usize(self.offset.bytes().wrapping_add(i.bytes()));
342 Pointer { offset: Size::from_bytes(res), ..self }
343 }
344
345 #[inline(always)]
346 pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
347 self.wrapping_offset(Size::from_bytes(i as u64), cx)
349 }
350}
351
352impl Pointer<CtfeProvenance> {
353 #[inline(always)]
356 pub fn prov_and_relative_offset(self) -> (CtfeProvenance, Size) {
357 (self.provenance, self.offset)
358 }
359}