]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/mir/interpret/mod.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / compiler / rustc_middle / src / mir / interpret / mod.rs
CommitLineData
e1599b0c 1//! An interpreter for MIR used in CTFE and by miri.
ff7c6d11
XL
2
3#[macro_export]
416331ca
XL
4macro_rules! err_unsup {
5 ($($tt:tt)*) => {
6 $crate::mir::interpret::InterpError::Unsupported(
7 $crate::mir::interpret::UnsupportedOpInfo::$($tt)*
8 )
9 };
10}
11
12#[macro_export]
13macro_rules! err_unsup_format {
14 ($($tt:tt)*) => { err_unsup!(Unsupported(format!($($tt)*))) };
15}
16
17#[macro_export]
18macro_rules! err_inval {
19 ($($tt:tt)*) => {
20 $crate::mir::interpret::InterpError::InvalidProgram(
21 $crate::mir::interpret::InvalidProgramInfo::$($tt)*
22 )
23 };
24}
25
26#[macro_export]
27macro_rules! err_ub {
28 ($($tt:tt)*) => {
29 $crate::mir::interpret::InterpError::UndefinedBehavior(
30 $crate::mir::interpret::UndefinedBehaviorInfo::$($tt)*
31 )
32 };
33}
34
35#[macro_export]
36macro_rules! err_ub_format {
37 ($($tt:tt)*) => { err_ub!(Ub(format!($($tt)*))) };
38}
39
416331ca
XL
40#[macro_export]
41macro_rules! err_exhaust {
42 ($($tt:tt)*) => {
43 $crate::mir::interpret::InterpError::ResourceExhaustion(
44 $crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
45 )
46 };
47}
48
ba9703b0
XL
49#[macro_export]
50macro_rules! err_machine_stop {
51 ($($tt:tt)*) => {
52 $crate::mir::interpret::InterpError::MachineStop(Box::new($($tt)*))
53 };
54}
55
56// In the `throw_*` macros, avoid `return` to make them work with `try {}`.
416331ca
XL
57#[macro_export]
58macro_rules! throw_unsup {
923072b8 59 ($($tt:tt)*) => { do yeet err_unsup!($($tt)*) };
416331ca
XL
60}
61
62#[macro_export]
63macro_rules! throw_unsup_format {
64 ($($tt:tt)*) => { throw_unsup!(Unsupported(format!($($tt)*))) };
65}
66
67#[macro_export]
68macro_rules! throw_inval {
923072b8 69 ($($tt:tt)*) => { do yeet err_inval!($($tt)*) };
416331ca
XL
70}
71
72#[macro_export]
73macro_rules! throw_ub {
923072b8 74 ($($tt:tt)*) => { do yeet err_ub!($($tt)*) };
416331ca
XL
75}
76
77#[macro_export]
78macro_rules! throw_ub_format {
79 ($($tt:tt)*) => { throw_ub!(Ub(format!($($tt)*))) };
80}
81
416331ca
XL
82#[macro_export]
83macro_rules! throw_exhaust {
923072b8 84 ($($tt:tt)*) => { do yeet err_exhaust!($($tt)*) };
ff7c6d11
XL
85}
86
60c5eb7d
XL
87#[macro_export]
88macro_rules! throw_machine_stop {
923072b8 89 ($($tt:tt)*) => { do yeet err_machine_stop!($($tt)*) };
60c5eb7d
XL
90}
91
a1dfa0c6 92mod allocation;
dfeec247 93mod error;
a1dfa0c6 94mod pointer;
dfeec247
XL
95mod queries;
96mod value;
ff7c6d11 97
ba9703b0
XL
98use std::convert::TryFrom;
99use std::fmt;
100use std::io;
1b1a35ee 101use std::io::{Read, Write};
136023e0 102use std::num::{NonZeroU32, NonZeroU64};
ba9703b0 103use std::sync::atomic::{AtomicU32, Ordering};
ff7c6d11 104
3dfed10e 105use rustc_ast::LitKind;
94b46f34 106use rustc_data_structures::fx::FxHashMap;
dfeec247 107use rustc_data_structures::sync::{HashMapExt, Lock};
94b46f34 108use rustc_data_structures::tiny_list::TinyList;
487cf647 109use rustc_errors::ErrorGuaranteed;
dfeec247 110use rustc_hir::def_id::DefId;
532ac7d7 111use rustc_macros::HashStable;
1b1a35ee 112use rustc_middle::ty::print::with_no_trimmed_paths;
3dfed10e 113use rustc_serialize::{Decodable, Encodable};
29967ef6 114use rustc_target::abi::Endian;
ba9703b0
XL
115
116use crate::mir;
3dfed10e 117use crate::ty::codec::{TyDecoder, TyEncoder};
ba9703b0
XL
118use crate::ty::subst::GenericArgKind;
119use crate::ty::{self, Instance, Ty, TyCtxt};
120
121pub use self::error::{
1b1a35ee 122 struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
923072b8
FG
123 EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo,
124 MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
125 UninitBytesAccess, UnsupportedOpInfo,
ba9703b0
XL
126};
127
f2b60f7d 128pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar};
ba9703b0 129
94222f64 130pub use self::allocation::{
487cf647
FG
131 alloc_range, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk,
132 InitChunkIter,
94222f64 133};
ba9703b0 134
136023e0 135pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
ff7c6d11 136
60c5eb7d
XL
137/// Uniquely identifies one of the following:
138/// - A constant
139/// - A static
3dfed10e 140#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
f2b60f7d 141#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
ff7c6d11
XL
142pub struct GlobalId<'tcx> {
143 /// For a constant or static, the `Instance` of the item itself.
144 /// For a promoted global, the `Instance` of the function they belong to.
145 pub instance: ty::Instance<'tcx>,
146
dc9dc135 147 /// The index for promoted globals within their function's `mir::Body`.
ff7c6d11
XL
148 pub promoted: Option<mir::Promoted>,
149}
150
a2a8927a 151impl<'tcx> GlobalId<'tcx> {
3dfed10e 152 pub fn display(self, tcx: TyCtxt<'tcx>) -> String {
5e7ed085 153 let instance_name = with_no_trimmed_paths!(tcx.def_path_str(self.instance.def.def_id()));
3dfed10e
XL
154 if let Some(promoted) = self.promoted {
155 format!("{}::{:?}", instance_name, promoted)
156 } else {
157 instance_name
158 }
159 }
160}
161
dfeec247
XL
162/// Input argument for `tcx.lit_to_const`.
163#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)]
164pub struct LitToConstInput<'tcx> {
165 /// The absolute value of the resultant constant.
166 pub lit: &'tcx LitKind,
167 /// The type of the constant.
168 pub ty: Ty<'tcx>,
169 /// If the constant is negative.
170 pub neg: bool,
171}
172
173/// Error type for `tcx.lit_to_const`.
174#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)]
175pub enum LitToConstError {
176 /// The literal's inferred type did not match the expected `ty` in the input.
177 /// This is used for graceful error handling (`delay_span_bug`) in
ba9703b0 178 /// type checking (`Const::from_anon_const`).
dfeec247 179 TypeError,
487cf647 180 Reported(ErrorGuaranteed),
dfeec247
XL
181}
182
183#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
136023e0 184pub struct AllocId(pub NonZeroU64);
ff7c6d11 185
f9f354fc
XL
186// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
187// all the Miri types.
dfeec247 188impl fmt::Debug for AllocId {
f9f354fc
XL
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 if f.alternate() { write!(f, "a{}", self.0) } else { write!(f, "alloc{}", self.0) }
ba9703b0
XL
191 }
192}
193
064997fb 194// No "Display" since AllocIds are not usually user-visible.
dfeec247 195
3dfed10e 196#[derive(TyDecodable, TyEncodable)]
0731742a 197enum AllocDiscriminant {
0531ce1d
XL
198 Alloc,
199 Fn,
064997fb 200 VTable,
0531ce1d
XL
201 Static,
202}
203
923072b8 204pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
0531ce1d 205 encoder: &mut E,
dc9dc135 206 tcx: TyCtxt<'tcx>,
0531ce1d 207 alloc_id: AllocId,
923072b8 208) {
f9f354fc 209 match tcx.global_alloc(alloc_id) {
dc9dc135 210 GlobalAlloc::Memory(alloc) => {
94b46f34 211 trace!("encoding {:?} with {:#?}", alloc_id, alloc);
923072b8
FG
212 AllocDiscriminant::Alloc.encode(encoder);
213 alloc.encode(encoder);
94b46f34 214 }
dc9dc135 215 GlobalAlloc::Function(fn_instance) => {
94b46f34 216 trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
923072b8
FG
217 AllocDiscriminant::Fn.encode(encoder);
218 fn_instance.encode(encoder);
94b46f34 219 }
064997fb
FG
220 GlobalAlloc::VTable(ty, poly_trait_ref) => {
221 trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id);
222 AllocDiscriminant::VTable.encode(encoder);
223 ty.encode(encoder);
224 poly_trait_ref.encode(encoder);
225 }
dc9dc135 226 GlobalAlloc::Static(did) => {
f9f354fc 227 assert!(!tcx.is_thread_local_static(did));
e1599b0c
XL
228 // References to statics doesn't need to know about their allocations,
229 // just about its `DefId`.
923072b8
FG
230 AllocDiscriminant::Static.encode(encoder);
231 did.encode(encoder);
94b46f34 232 }
0531ce1d 233 }
0531ce1d
XL
234}
235
94b46f34
XL
236// Used to avoid infinite recursion when decoding cyclic allocations.
237type DecodingSessionId = NonZeroU32;
238
239#[derive(Clone)]
240enum State {
241 Empty,
242 InProgressNonAlloc(TinyList<DecodingSessionId>),
243 InProgress(TinyList<DecodingSessionId>, AllocId),
244 Done(AllocId),
245}
246
247pub struct AllocDecodingState {
e1599b0c
XL
248 // For each `AllocId`, we keep track of which decoding state it's currently in.
249 decoding_state: Vec<Lock<State>>,
94b46f34
XL
250 // The offsets of each allocation in the data stream.
251 data_offsets: Vec<u32>,
252}
253
254impl AllocDecodingState {
17df50a5 255 #[inline]
0bf4aa26 256 pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> {
94b46f34
XL
257 static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0);
258 let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst);
259
e1599b0c 260 // Make sure this is never zero.
94b46f34
XL
261 let session_id = DecodingSessionId::new((counter & 0x7FFFFFFF) + 1).unwrap();
262
dfeec247 263 AllocDecodingSession { state: self, session_id }
94b46f34
XL
264 }
265
e1599b0c
XL
266 pub fn new(data_offsets: Vec<u32>) -> Self {
267 let decoding_state = vec![Lock::new(State::Empty); data_offsets.len()];
94b46f34 268
dfeec247 269 Self { decoding_state, data_offsets }
94b46f34
XL
270 }
271}
272
273#[derive(Copy, Clone)]
274pub struct AllocDecodingSession<'s> {
275 state: &'s AllocDecodingState,
276 session_id: DecodingSessionId,
277}
278
279impl<'s> AllocDecodingSession<'s> {
e1599b0c 280 /// Decodes an `AllocId` in a thread-safe way.
5099ac24 281 pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId
dc9dc135 282 where
923072b8 283 D: TyDecoder<I = TyCtxt<'tcx>>,
94b46f34 284 {
e1599b0c 285 // Read the index of the allocation.
5099ac24 286 let idx = usize::try_from(decoder.read_u32()).unwrap();
ba9703b0 287 let pos = usize::try_from(self.state.data_offsets[idx]).unwrap();
94b46f34 288
e1599b0c
XL
289 // Decode the `AllocDiscriminant` now so that we know if we have to reserve an
290 // `AllocId`.
94b46f34 291 let (alloc_kind, pos) = decoder.with_position(pos, |decoder| {
5099ac24
FG
292 let alloc_kind = AllocDiscriminant::decode(decoder);
293 (alloc_kind, decoder.position())
294 });
94b46f34 295
e1599b0c 296 // Check the decoding state to see if it's already decoded or if we should
94b46f34
XL
297 // decode it here.
298 let alloc_id = {
299 let mut entry = self.state.decoding_state[idx].lock();
300
301 match *entry {
302 State::Done(alloc_id) => {
5099ac24 303 return alloc_id;
94b46f34
XL
304 }
305 ref mut entry @ State::Empty => {
e1599b0c 306 // We are allowed to decode.
94b46f34 307 match alloc_kind {
0731742a 308 AllocDiscriminant::Alloc => {
94b46f34 309 // If this is an allocation, we need to reserve an
e1599b0c 310 // `AllocId` so we can decode cyclic graphs.
923072b8 311 let alloc_id = decoder.interner().reserve_alloc_id();
dfeec247
XL
312 *entry =
313 State::InProgress(TinyList::new_single(self.session_id), alloc_id);
94b46f34 314 Some(alloc_id)
dfeec247 315 }
064997fb
FG
316 AllocDiscriminant::Fn
317 | AllocDiscriminant::Static
318 | AllocDiscriminant::VTable => {
e1599b0c
XL
319 // Fns and statics cannot be cyclic, and their `AllocId`
320 // is determined later by interning.
dfeec247
XL
321 *entry =
322 State::InProgressNonAlloc(TinyList::new_single(self.session_id));
94b46f34
XL
323 None
324 }
325 }
326 }
327 State::InProgressNonAlloc(ref mut sessions) => {
328 if sessions.contains(&self.session_id) {
e1599b0c 329 bug!("this should be unreachable");
94b46f34 330 } else {
e1599b0c 331 // Start decoding concurrently.
94b46f34
XL
332 sessions.insert(self.session_id);
333 None
334 }
335 }
336 State::InProgress(ref mut sessions, alloc_id) => {
337 if sessions.contains(&self.session_id) {
338 // Don't recurse.
5099ac24 339 return alloc_id;
94b46f34 340 } else {
e1599b0c 341 // Start decoding concurrently.
94b46f34
XL
342 sessions.insert(self.session_id);
343 Some(alloc_id)
344 }
345 }
346 }
347 };
348
e1599b0c 349 // Now decode the actual data.
94b46f34
XL
350 let alloc_id = decoder.with_position(pos, |decoder| {
351 match alloc_kind {
0731742a 352 AllocDiscriminant::Alloc => {
5e7ed085 353 let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
e1599b0c 354 // We already have a reserved `AllocId`.
94b46f34 355 let alloc_id = alloc_id.unwrap();
e1599b0c 356 trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
923072b8 357 decoder.interner().set_alloc_id_same_memory(alloc_id, alloc);
5099ac24 358 alloc_id
dfeec247 359 }
0731742a 360 AllocDiscriminant::Fn => {
94b46f34 361 assert!(alloc_id.is_none());
e1599b0c 362 trace!("creating fn alloc ID");
5099ac24 363 let instance = ty::Instance::decode(decoder);
94b46f34 364 trace!("decoded fn alloc instance: {:?}", instance);
923072b8 365 let alloc_id = decoder.interner().create_fn_alloc(instance);
5099ac24 366 alloc_id
dfeec247 367 }
064997fb
FG
368 AllocDiscriminant::VTable => {
369 assert!(alloc_id.is_none());
370 trace!("creating vtable alloc ID");
371 let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
372 let poly_trait_ref =
373 <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
374 trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
375 let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref);
376 alloc_id
377 }
0731742a 378 AllocDiscriminant::Static => {
94b46f34 379 assert!(alloc_id.is_none());
e1599b0c 380 trace!("creating extern static alloc ID");
5099ac24 381 let did = <DefId as Decodable<D>>::decode(decoder);
e1599b0c 382 trace!("decoded static def-ID: {:?}", did);
923072b8 383 let alloc_id = decoder.interner().create_static_alloc(did);
5099ac24 384 alloc_id
94b46f34
XL
385 }
386 }
5099ac24 387 });
94b46f34
XL
388
389 self.state.decoding_state[idx].with_lock(|entry| {
390 *entry = State::Done(alloc_id);
391 });
392
5099ac24 393 alloc_id
0531ce1d
XL
394 }
395}
396
dc9dc135
XL
397/// An allocation in the global (tcx-managed) memory can be either a function pointer,
398/// a static, or a "real" allocation with some data in it.
3dfed10e 399#[derive(Debug, Clone, Eq, PartialEq, Hash, TyDecodable, TyEncodable, HashStable)]
dc9dc135 400pub enum GlobalAlloc<'tcx> {
e1599b0c 401 /// The alloc ID is used as a function pointer.
94b46f34 402 Function(Instance<'tcx>),
064997fb
FG
403 /// This alloc ID points to a symbolic (not-reified) vtable.
404 VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
9fa01778 405 /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
b7449926 406 /// This is also used to break the cycle in recursive statics.
94b46f34 407 Static(DefId),
9fa01778 408 /// The alloc ID points to memory.
5e7ed085 409 Memory(ConstAllocation<'tcx>),
94b46f34
XL
410}
411
a2a8927a 412impl<'tcx> GlobalAlloc<'tcx> {
f9f354fc
XL
413 /// Panics if the `GlobalAlloc` does not refer to an `GlobalAlloc::Memory`
414 #[track_caller]
415 #[inline]
5e7ed085 416 pub fn unwrap_memory(&self) -> ConstAllocation<'tcx> {
f9f354fc
XL
417 match *self {
418 GlobalAlloc::Memory(mem) => mem,
419 _ => bug!("expected memory, got {:?}", self),
420 }
421 }
422
423 /// Panics if the `GlobalAlloc` is not `GlobalAlloc::Function`
424 #[track_caller]
425 #[inline]
426 pub fn unwrap_fn(&self) -> Instance<'tcx> {
427 match *self {
428 GlobalAlloc::Function(instance) => instance,
429 _ => bug!("expected function, got {:?}", self),
430 }
431 }
064997fb
FG
432
433 /// Panics if the `GlobalAlloc` is not `GlobalAlloc::VTable`
434 #[track_caller]
435 #[inline]
436 pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
437 match *self {
438 GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref),
439 _ => bug!("expected vtable, got {:?}", self),
440 }
441 }
f9f354fc
XL
442}
443
923072b8 444pub(crate) struct AllocMap<'tcx> {
e1599b0c 445 /// Maps `AllocId`s to their corresponding allocations.
dc9dc135 446 alloc_map: FxHashMap<AllocId, GlobalAlloc<'tcx>>,
94b46f34 447
dc9dc135
XL
448 /// Used to ensure that statics and functions only get one associated `AllocId`.
449 /// Should never contain a `GlobalAlloc::Memory`!
e1599b0c
XL
450 //
451 // FIXME: Should we just have two separate dedup maps for statics and functions each?
dc9dc135 452 dedup: FxHashMap<GlobalAlloc<'tcx>, AllocId>,
94b46f34 453
9fa01778 454 /// The `AllocId` to assign to the next requested ID.
e1599b0c 455 /// Always incremented; never gets smaller.
94b46f34
XL
456 next_id: AllocId,
457}
458
0731742a 459impl<'tcx> AllocMap<'tcx> {
923072b8 460 pub(crate) fn new() -> Self {
136023e0
XL
461 AllocMap {
462 alloc_map: Default::default(),
463 dedup: Default::default(),
464 next_id: AllocId(NonZeroU64::new(1).unwrap()),
465 }
94b46f34 466 }
f9f354fc 467 fn reserve(&mut self) -> AllocId {
94b46f34 468 let next = self.next_id;
dfeec247
XL
469 self.next_id.0 = self.next_id.0.checked_add(1).expect(
470 "You overflowed a u64 by incrementing by 1... \
471 You've just earned yourself a free drink if we ever meet. \
472 Seriously, how did you do that?!",
473 );
94b46f34
XL
474 next
475 }
f9f354fc
XL
476}
477
478impl<'tcx> TyCtxt<'tcx> {
479 /// Obtains a new allocation ID that can be referenced but does not
480 /// yet have an allocation backing it.
481 ///
482 /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such
483 /// an `AllocId` from a query.
1b1a35ee 484 pub fn reserve_alloc_id(self) -> AllocId {
f9f354fc
XL
485 self.alloc_map.lock().reserve()
486 }
94b46f34 487
e1599b0c 488 /// Reserves a new ID *if* this allocation has not been dedup-reserved before.
064997fb
FG
489 /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we
490 /// don't want to dedup IDs for "real" memory!
1b1a35ee 491 fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId {
f9f354fc 492 let mut alloc_map = self.alloc_map.lock();
dc9dc135 493 match alloc {
064997fb 494 GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {}
dc9dc135
XL
495 GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"),
496 }
f9f354fc 497 if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) {
94b46f34
XL
498 return alloc_id;
499 }
f9f354fc 500 let id = alloc_map.reserve();
064997fb 501 debug!("creating alloc {alloc:?} with id {id:?}");
f9f354fc
XL
502 alloc_map.alloc_map.insert(id, alloc.clone());
503 alloc_map.dedup.insert(alloc, id);
94b46f34
XL
504 id
505 }
506
dc9dc135
XL
507 /// Generates an `AllocId` for a static or return a cached one in case this function has been
508 /// called on the same static before.
1b1a35ee 509 pub fn create_static_alloc(self, static_id: DefId) -> AllocId {
dc9dc135
XL
510 self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
511 }
512
513 /// Generates an `AllocId` for a function. Depending on the function type,
514 /// this might get deduplicated or assigned a new ID each time.
1b1a35ee 515 pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
9fa01778
XL
516 // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
517 // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
518 // duplicated across crates.
519 // We thus generate a new `AllocId` for every mention of a function. This means that
520 // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
521 // However, formatting code relies on function identity (see #58320), so we only do
522 // this for generic functions. Lifetime parameters are ignored.
29967ef6
XL
523 let is_generic = instance
524 .substs
525 .into_iter()
526 .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
9fa01778 527 if is_generic {
e1599b0c 528 // Get a fresh ID.
f9f354fc
XL
529 let mut alloc_map = self.alloc_map.lock();
530 let id = alloc_map.reserve();
531 alloc_map.alloc_map.insert(id, GlobalAlloc::Function(instance));
9fa01778
XL
532 id
533 } else {
e1599b0c 534 // Deduplicate.
dc9dc135 535 self.reserve_and_set_dedup(GlobalAlloc::Function(instance))
9fa01778 536 }
94b46f34
XL
537 }
538
064997fb
FG
539 /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
540 pub fn create_vtable_alloc(
541 self,
542 ty: Ty<'tcx>,
543 poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
544 ) -> AllocId {
545 self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref))
546 }
547
e1599b0c 548 /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical
dc9dc135
XL
549 /// `Allocation` with a different `AllocId`.
550 /// Statics with identical content will still point to the same `Allocation`, i.e.,
551 /// their data will be deduplicated through `Allocation` interning -- but they
552 /// are different places in memory and as such need different IDs.
5e7ed085 553 pub fn create_memory_alloc(self, mem: ConstAllocation<'tcx>) -> AllocId {
f9f354fc 554 let id = self.reserve_alloc_id();
dc9dc135
XL
555 self.set_alloc_id_memory(id, mem);
556 id
557 }
558
532ac7d7 559 /// Returns `None` in case the `AllocId` is dangling. An `InterpretCx` can still have a
0731742a
XL
560 /// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is
561 /// illegal and will likely ICE.
562 /// This function exists to allow const eval to detect the difference between evaluation-
563 /// local dangling pointers and allocations in constants/statics.
dc9dc135 564 #[inline]
064997fb 565 pub fn try_get_global_alloc(self, id: AllocId) -> Option<GlobalAlloc<'tcx>> {
f9f354fc 566 self.alloc_map.lock().alloc_map.get(&id).cloned()
94b46f34
XL
567 }
568
f9f354fc
XL
569 #[inline]
570 #[track_caller]
571 /// Panics in case the `AllocId` is dangling. Since that is impossible for `AllocId`s in
572 /// constants (as all constants must pass interning and validation that check for dangling
573 /// ids), this function is frequently used throughout rustc, but should not be used within
574 /// the miri engine.
1b1a35ee 575 pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> {
064997fb 576 match self.try_get_global_alloc(id) {
f9f354fc 577 Some(alloc) => alloc,
064997fb 578 None => bug!("could not find allocation for {id:?}"),
e74abb32
XL
579 }
580 }
581
e1599b0c 582 /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
0731742a 583 /// call this function twice, even with the same `Allocation` will ICE the compiler.
5e7ed085 584 pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
f9f354fc 585 if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
064997fb 586 bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}");
94b46f34
XL
587 }
588 }
589
e1599b0c 590 /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
0731742a 591 /// twice for the same `(AllocId, Allocation)` pair.
5e7ed085 592 fn set_alloc_id_same_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
f9f354fc 593 self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
94b46f34
XL
594 }
595}
596
94b46f34
XL
597////////////////////////////////////////////////////////////////////////////////
598// Methods to access integers in the target endianness
599////////////////////////////////////////////////////////////////////////////////
600
dc9dc135 601#[inline]
94b46f34 602pub fn write_target_uint(
ba9703b0 603 endianness: Endian,
94b46f34
XL
604 mut target: &mut [u8],
605 data: u128,
606) -> Result<(), io::Error> {
1b1a35ee
XL
607 // This u128 holds an "any-size uint" (since smaller uints can fits in it)
608 // So we do not write all bytes of the u128, just the "payload".
94b46f34 609 match endianness {
1b1a35ee
XL
610 Endian::Little => target.write(&data.to_le_bytes())?,
611 Endian::Big => target.write(&data.to_be_bytes()[16 - target.len()..])?,
612 };
613 debug_assert!(target.len() == 0); // We should have filled the target buffer.
614 Ok(())
94b46f34
XL
615}
616
dc9dc135 617#[inline]
ba9703b0 618pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, io::Error> {
1b1a35ee
XL
619 // This u128 holds an "any-size uint" (since smaller uints can fits in it)
620 let mut buf = [0u8; std::mem::size_of::<u128>()];
621 // So we do not read exactly 16 bytes into the u128, just the "payload".
622 let uint = match endianness {
623 Endian::Little => {
624 source.read(&mut buf)?;
625 Ok(u128::from_le_bytes(buf))
626 }
627 Endian::Big => {
628 source.read(&mut buf[16 - source.len()..])?;
629 Ok(u128::from_be_bytes(buf))
630 }
631 };
632 debug_assert!(source.len() == 0); // We should have consumed the source buffer.
633 uint
94b46f34 634}