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(#[automatically_derived]
impl ::core::marker::Copy for CtfeProvenance { }Copy, #[automatically_derived]
impl ::core::clone::Clone for CtfeProvenance {
#[inline]
fn clone(&self) -> CtfeProvenance {
let _: ::core::clone::AssertParamIsClone<NonZero<u64>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::cmp::Eq for CtfeProvenance {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<NonZero<u64>>;
}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for CtfeProvenance {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}Hash, #[automatically_derived]
impl ::core::cmp::Ord for CtfeProvenance {
#[inline]
fn cmp(&self, other: &CtfeProvenance) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}Ord, #[automatically_derived]
impl ::core::cmp::PartialEq for CtfeProvenance {
#[inline]
fn eq(&self, other: &CtfeProvenance) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for CtfeProvenance {
#[inline]
fn partial_cmp(&self, other: &CtfeProvenance)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
}
}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 if !(prov.alloc_id() == value) {
{
::core::panicking::panic_fmt(format_args!("`AllocId` with the highest bits set cannot be used in CTFE"));
}
};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 f.write_fmt(format_args!("<imm>"))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 f.write_fmt(format_args!("+{0:#x}", ptr.offset.bytes()))write!(f, "+{:#x}", ptr.offset.bytes())?;
180 }
181 if ptr.provenance.immutable() {
183 f.write_fmt(format_args!("<imm>"))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 f.write_fmt(format_args!("{0:#?}", ptr.provenance))write!(f, "{:#?}", ptr.provenance)?;
206 } else {
207 f.write_fmt(format_args!("{0:?}", ptr.provenance))write!(f, "{:?}", ptr.provenance)?;
208 }
209 if ptr.offset.bytes() > 0 {
211 f.write_fmt(format_args!("+{0:#x}", ptr.offset.bytes()))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(#[automatically_derived]
impl<Prov: ::core::marker::Copy> ::core::marker::Copy for Pointer<Prov> { }Copy, #[automatically_derived]
impl<Prov: ::core::clone::Clone> ::core::clone::Clone for Pointer<Prov> {
#[inline]
fn clone(&self) -> Pointer<Prov> {
Pointer {
offset: ::core::clone::Clone::clone(&self.offset),
provenance: ::core::clone::Clone::clone(&self.provenance),
}
}
}Clone, #[automatically_derived]
impl<Prov: ::core::cmp::Eq> ::core::cmp::Eq for Pointer<Prov> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Size>;
let _: ::core::cmp::AssertParamIsEq<Prov>;
}
}Eq, #[automatically_derived]
impl<Prov: ::core::cmp::PartialEq> ::core::cmp::PartialEq for Pointer<Prov> {
#[inline]
fn eq(&self, other: &Pointer<Prov>) -> bool {
self.offset == other.offset && self.provenance == other.provenance
}
}PartialEq, const _: () =
{
impl<'tcx, Prov, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
::rustc_serialize::Encodable<__E> for Pointer<Prov> where
Prov: ::rustc_serialize::Encodable<__E> {
fn encode(&self, __encoder: &mut __E) {
match *self {
Pointer {
offset: ref __binding_0, provenance: ref __binding_1 } => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
}
}
}
}
};TyEncodable, const _: () =
{
impl<'tcx, Prov, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
::rustc_serialize::Decodable<__D> for Pointer<Prov> where
Prov: ::rustc_serialize::Decodable<__D> {
fn decode(__decoder: &mut __D) -> Self {
Pointer {
offset: ::rustc_serialize::Decodable::decode(__decoder),
provenance: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};TyDecodable, #[automatically_derived]
impl<Prov: ::core::hash::Hash> ::core::hash::Hash for Pointer<Prov> {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.offset, state);
::core::hash::Hash::hash(&self.provenance, state)
}
}Hash)]
225#[derive(const _: () =
{
impl<'__ctx, Prov>
::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
for Pointer<Prov> where
Prov: ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
{
#[inline]
fn hash_stable(&self,
__hcx:
&mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
match *self {
Pointer {
offset: ref __binding_0, provenance: ref __binding_1 } => {
{ __binding_0.hash_stable(__hcx, __hasher); }
{ __binding_1.hash_stable(__hcx, __hasher); }
}
}
}
}
};HashStable)]
226pub struct Pointer<Prov = CtfeProvenance> {
227 pub(super) offset: Size, pub provenance: Prov,
229}
230
231const _: [(); 16] = [(); ::std::mem::size_of::<Pointer>()];static_assert_size!(Pointer, 16);
232const _: [(); 16] =
[(); ::std::mem::size_of::<Pointer<Option<CtfeProvenance>>>()];static_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 => f.write_fmt(format_args!("{0:#x}[noalloc]", self.offset.bytes()))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 f.write_fmt(format_args!("null pointer"))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 if !Prov::OFFSET_IS_ADDR {
::core::panicking::panic("assertion failed: Prov::OFFSET_IS_ADDR")
};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}