1use std::assert_matches::assert_matches;
5
6use either::{Either, Left, Right};
7use rustc_abi as abi;
8use rustc_abi::{BackendRepr, HasDataLayout, Size};
9use rustc_hir::def::Namespace;
10use rustc_middle::mir::interpret::ScalarSizeMismatch;
11use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
12use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
13use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
14use rustc_middle::{bug, mir, span_bug, ty};
15use tracing::trace;
16
17use super::{
18 CtfeProvenance, Frame, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta,
19 OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub,
20 from_known_layout, interp_ok, mir_assign_valid_types, throw_ub,
21};
22
23#[derive(Copy, Clone, Debug)]
31pub enum Immediate<Prov: Provenance = CtfeProvenance> {
32 Scalar(Scalar<Prov>),
34 ScalarPair(Scalar<Prov>, Scalar<Prov>),
37 Uninit,
39}
40
41impl<Prov: Provenance> From<Scalar<Prov>> for Immediate<Prov> {
42 #[inline(always)]
43 fn from(val: Scalar<Prov>) -> Self {
44 Immediate::Scalar(val)
45 }
46}
47
48impl<Prov: Provenance> Immediate<Prov> {
49 pub fn new_pointer_with_meta(
50 ptr: Pointer<Option<Prov>>,
51 meta: MemPlaceMeta<Prov>,
52 cx: &impl HasDataLayout,
53 ) -> Self {
54 let ptr = Scalar::from_maybe_pointer(ptr, cx);
55 match meta {
56 MemPlaceMeta::None => Immediate::from(ptr),
57 MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(ptr, meta),
58 }
59 }
60
61 pub fn new_slice(ptr: Pointer<Option<Prov>>, len: u64, cx: &impl HasDataLayout) -> Self {
62 Immediate::ScalarPair(
63 Scalar::from_maybe_pointer(ptr, cx),
64 Scalar::from_target_usize(len, cx),
65 )
66 }
67
68 pub fn new_dyn_trait(
69 val: Pointer<Option<Prov>>,
70 vtable: Pointer<Option<Prov>>,
71 cx: &impl HasDataLayout,
72 ) -> Self {
73 Immediate::ScalarPair(
74 Scalar::from_maybe_pointer(val, cx),
75 Scalar::from_maybe_pointer(vtable, cx),
76 )
77 }
78
79 #[inline]
80 #[cfg_attr(debug_assertions, track_caller)] pub fn to_scalar(self) -> Scalar<Prov> {
82 match self {
83 Immediate::Scalar(val) => val,
84 Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"),
85 Immediate::Uninit => bug!("Got uninit where a scalar was expected"),
86 }
87 }
88
89 #[inline]
90 #[cfg_attr(debug_assertions, track_caller)] pub fn to_scalar_int(self) -> ScalarInt {
92 self.to_scalar().try_to_scalar_int().unwrap()
93 }
94
95 #[inline]
96 #[cfg_attr(debug_assertions, track_caller)] pub fn to_scalar_pair(self) -> (Scalar<Prov>, Scalar<Prov>) {
98 match self {
99 Immediate::ScalarPair(val1, val2) => (val1, val2),
100 Immediate::Scalar(..) => bug!("Got a scalar where a scalar pair was expected"),
101 Immediate::Uninit => bug!("Got uninit where a scalar pair was expected"),
102 }
103 }
104
105 #[inline]
107 #[cfg_attr(debug_assertions, track_caller)] pub fn to_scalar_and_meta(self) -> (Scalar<Prov>, MemPlaceMeta<Prov>) {
109 match self {
110 Immediate::ScalarPair(val1, val2) => (val1, MemPlaceMeta::Meta(val2)),
111 Immediate::Scalar(val) => (val, MemPlaceMeta::None),
112 Immediate::Uninit => bug!("Got uninit where a scalar or scalar pair was expected"),
113 }
114 }
115
116 pub fn assert_matches_abi(self, abi: BackendRepr, msg: &str, cx: &impl HasDataLayout) {
118 match (self, abi) {
119 (Immediate::Scalar(scalar), BackendRepr::Scalar(s)) => {
120 assert_eq!(scalar.size(), s.size(cx), "{msg}: scalar value has wrong size");
121 if !matches!(s.primitive(), abi::Primitive::Pointer(..)) {
122 assert!(
124 matches!(scalar, Scalar::Int(..)),
125 "{msg}: scalar value should be an integer, but has provenance"
126 );
127 }
128 }
129 (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => {
130 assert_eq!(
131 a_val.size(),
132 a.size(cx),
133 "{msg}: first component of scalar pair has wrong size"
134 );
135 if !matches!(a.primitive(), abi::Primitive::Pointer(..)) {
136 assert!(
137 matches!(a_val, Scalar::Int(..)),
138 "{msg}: first component of scalar pair should be an integer, but has provenance"
139 );
140 }
141 assert_eq!(
142 b_val.size(),
143 b.size(cx),
144 "{msg}: second component of scalar pair has wrong size"
145 );
146 if !matches!(b.primitive(), abi::Primitive::Pointer(..)) {
147 assert!(
148 matches!(b_val, Scalar::Int(..)),
149 "{msg}: second component of scalar pair should be an integer, but has provenance"
150 );
151 }
152 }
153 (Immediate::Uninit, _) => {
154 assert!(abi.is_sized(), "{msg}: unsized immediates are not a thing");
155 }
156 _ => {
157 bug!("{msg}: value {self:?} does not match ABI {abi:?})",)
158 }
159 }
160 }
161
162 pub fn clear_provenance<'tcx>(&mut self) -> InterpResult<'tcx> {
163 match self {
164 Immediate::Scalar(s) => {
165 s.clear_provenance()?;
166 }
167 Immediate::ScalarPair(a, b) => {
168 a.clear_provenance()?;
169 b.clear_provenance()?;
170 }
171 Immediate::Uninit => {}
172 }
173 interp_ok(())
174 }
175}
176
177#[derive(Clone)]
180pub struct ImmTy<'tcx, Prov: Provenance = CtfeProvenance> {
181 imm: Immediate<Prov>,
182 pub layout: TyAndLayout<'tcx>,
183}
184
185impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 fn p<'a, 'tcx, Prov: Provenance>(
189 cx: &mut FmtPrinter<'a, 'tcx>,
190 s: Scalar<Prov>,
191 ty: Ty<'tcx>,
192 ) -> Result<(), std::fmt::Error> {
193 match s {
194 Scalar::Int(int) => cx.pretty_print_const_scalar_int(int, ty, true),
195 Scalar::Ptr(ptr, _sz) => {
196 cx.pretty_print_const_pointer(ptr, ty)
200 }
201 }
202 }
203 ty::tls::with(|tcx| {
204 match self.imm {
205 Immediate::Scalar(s) => {
206 if let Some(ty) = tcx.lift(self.layout.ty) {
207 let s =
208 FmtPrinter::print_string(tcx, Namespace::ValueNS, |cx| p(cx, s, ty))?;
209 f.write_str(&s)?;
210 return Ok(());
211 }
212 write!(f, "{:x}: {}", s, self.layout.ty)
213 }
214 Immediate::ScalarPair(a, b) => {
215 write!(f, "({:x}, {:x}): {}", a, b, self.layout.ty)
217 }
218 Immediate::Uninit => {
219 write!(f, "uninit: {}", self.layout.ty)
220 }
221 }
222 })
223 }
224}
225
226impl<Prov: Provenance> std::fmt::Debug for ImmTy<'_, Prov> {
227 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228 f.debug_struct("ImmTy")
230 .field("imm", &self.imm)
231 .field("ty", &format_args!("{}", self.layout.ty))
232 .finish()
233 }
234}
235
236impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> {
237 type Target = Immediate<Prov>;
238 #[inline(always)]
239 fn deref(&self) -> &Immediate<Prov> {
240 &self.imm
241 }
242}
243
244impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
245 #[inline]
246 pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
247 debug_assert!(layout.backend_repr.is_scalar(), "`ImmTy::from_scalar` on non-scalar layout");
248 debug_assert_eq!(val.size(), layout.size);
249 ImmTy { imm: val.into(), layout }
250 }
251
252 #[inline]
253 pub fn from_scalar_pair(a: Scalar<Prov>, b: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
254 debug_assert!(
255 matches!(layout.backend_repr, BackendRepr::ScalarPair(..)),
256 "`ImmTy::from_scalar_pair` on non-scalar-pair layout"
257 );
258 let imm = Immediate::ScalarPair(a, b);
259 ImmTy { imm, layout }
260 }
261
262 #[inline(always)]
263 pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self {
264 debug_assert!(
266 match (imm, layout.backend_repr) {
267 (Immediate::Scalar(..), BackendRepr::Scalar(..)) => true,
268 (Immediate::ScalarPair(..), BackendRepr::ScalarPair(..)) => true,
269 (Immediate::Uninit, _) if layout.is_sized() => true,
270 _ => false,
271 },
272 "immediate {imm:?} does not fit to layout {layout:?}",
273 );
274 ImmTy { imm, layout }
275 }
276
277 #[inline]
278 pub fn uninit(layout: TyAndLayout<'tcx>) -> Self {
279 debug_assert!(layout.is_sized(), "immediates must be sized");
280 ImmTy { imm: Immediate::Uninit, layout }
281 }
282
283 #[inline]
284 pub fn from_scalar_int(s: ScalarInt, layout: TyAndLayout<'tcx>) -> Self {
285 Self::from_scalar(Scalar::from(s), layout)
286 }
287
288 #[inline]
289 pub fn from_uint(i: impl Into<u128>, layout: TyAndLayout<'tcx>) -> Self {
290 Self::from_scalar(Scalar::from_uint(i, layout.size), layout)
291 }
292
293 #[inline]
294 pub fn from_int(i: impl Into<i128>, layout: TyAndLayout<'tcx>) -> Self {
295 Self::from_scalar(Scalar::from_int(i, layout.size), layout)
296 }
297
298 #[inline]
299 pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
300 let layout = tcx
302 .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool))
303 .unwrap();
304 Self::from_scalar(Scalar::from_bool(b), layout)
305 }
306
307 #[inline]
308 pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
309 let ty = tcx.ty_ordering_enum(None);
311 let layout =
312 tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
313 Self::from_scalar(Scalar::from_i8(c as i8), layout)
314 }
315
316 pub fn from_pair(a: Self, b: Self, cx: &(impl HasTypingEnv<'tcx> + HasTyCtxt<'tcx>)) -> Self {
317 let layout = cx
318 .tcx()
319 .layout_of(
320 cx.typing_env().as_query_input(Ty::new_tup(cx.tcx(), &[a.layout.ty, b.layout.ty])),
321 )
322 .unwrap();
323 Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)
324 }
325
326 #[inline]
329 pub fn to_scalar_int(&self) -> InterpResult<'tcx, ScalarInt> {
330 let s = self.to_scalar().to_scalar_int()?;
331 if s.size() != self.layout.size {
332 throw_ub!(ScalarSizeMismatch(ScalarSizeMismatch {
333 target_size: self.layout.size.bytes(),
334 data_size: s.size().bytes(),
335 }));
336 }
337 interp_ok(s)
338 }
339
340 #[inline]
341 pub fn to_const_int(self) -> ConstInt {
342 assert!(self.layout.ty.is_integral());
343 let int = self.imm.to_scalar_int();
344 assert_eq!(int.size(), self.layout.size);
345 ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral())
346 }
347
348 #[inline]
349 #[cfg_attr(debug_assertions, track_caller)] pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>)) -> (Self, Self) {
351 let layout = self.layout;
352 let (val0, val1) = self.to_scalar_pair();
353 (
354 ImmTy::from_scalar(val0, layout.field(cx, 0)),
355 ImmTy::from_scalar(val1, layout.field(cx, 1)),
356 )
357 }
358
359 fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
363 if cfg!(debug_assertions) {
365 self.assert_matches_abi(
366 self.layout.backend_repr,
367 "invalid input to Immediate::offset",
368 cx,
369 );
370 }
371 assert!(
375 offset + layout.size <= self.layout.size,
376 "attempting to project to field at offset {} with size {} into immediate with layout {:#?}",
377 offset.bytes(),
378 layout.size.bytes(),
379 self.layout,
380 );
381 let inner_val: Immediate<_> = match (**self, self.layout.backend_repr) {
384 (Immediate::Uninit, _) => Immediate::Uninit,
386 _ if layout.is_uninhabited() => Immediate::Uninit,
390 _ if layout.is_zst() => Immediate::Uninit,
393 _ if matches!(layout.backend_repr, BackendRepr::Memory { .. })
396 && matches!(layout.variants, abi::Variants::Single { .. })
397 && matches!(&layout.fields, abi::FieldsShape::Arbitrary { offsets, .. } if offsets.len() == 0) =>
398 {
399 Immediate::Uninit
400 }
401 _ if layout.size == self.layout.size => {
403 assert_eq!(offset.bytes(), 0);
404 **self
405 }
406 (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => {
408 Immediate::from(if offset.bytes() == 0 {
409 a_val
410 } else {
411 assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi));
412 b_val
413 })
414 }
415 _ => bug!(
417 "invalid field access on immediate {} at offset {}, original layout {:#?}",
418 self,
419 offset.bytes(),
420 self.layout
421 ),
422 };
423 inner_val.assert_matches_abi(
425 layout.backend_repr,
426 "invalid field type in Immediate::offset",
427 cx,
428 );
429
430 ImmTy::from_immediate(inner_val, layout)
431 }
432}
433
434impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
435 #[inline(always)]
436 fn layout(&self) -> TyAndLayout<'tcx> {
437 self.layout
438 }
439
440 #[inline(always)]
441 fn meta(&self) -> MemPlaceMeta<Prov> {
442 debug_assert!(self.layout.is_sized()); MemPlaceMeta::None
444 }
445
446 fn offset_with_meta<M: Machine<'tcx, Provenance = Prov>>(
447 &self,
448 offset: Size,
449 _mode: OffsetMode,
450 meta: MemPlaceMeta<Prov>,
451 layout: TyAndLayout<'tcx>,
452 ecx: &InterpCx<'tcx, M>,
453 ) -> InterpResult<'tcx, Self> {
454 assert_matches!(meta, MemPlaceMeta::None); interp_ok(self.offset_(offset, layout, ecx))
456 }
457
458 #[inline(always)]
459 fn to_op<M: Machine<'tcx, Provenance = Prov>>(
460 &self,
461 _ecx: &InterpCx<'tcx, M>,
462 ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
463 interp_ok(self.clone().into())
464 }
465}
466
467#[derive(Copy, Clone, Debug)]
471pub(super) enum Operand<Prov: Provenance = CtfeProvenance> {
472 Immediate(Immediate<Prov>),
473 Indirect(MemPlace<Prov>),
474}
475
476#[derive(Clone)]
477pub struct OpTy<'tcx, Prov: Provenance = CtfeProvenance> {
478 op: Operand<Prov>, pub layout: TyAndLayout<'tcx>,
480}
481
482impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> {
483 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
484 f.debug_struct("OpTy")
486 .field("op", &self.op)
487 .field("ty", &format_args!("{}", self.layout.ty))
488 .finish()
489 }
490}
491
492impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
493 #[inline(always)]
494 fn from(val: ImmTy<'tcx, Prov>) -> Self {
495 OpTy { op: Operand::Immediate(val.imm), layout: val.layout }
496 }
497}
498
499impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
500 #[inline(always)]
501 fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self {
502 OpTy { op: Operand::Indirect(*mplace.mplace()), layout: mplace.layout }
503 }
504}
505
506impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
507 #[inline(always)]
508 pub(super) fn op(&self) -> &Operand<Prov> {
509 &self.op
510 }
511}
512
513impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> {
514 #[inline(always)]
515 fn layout(&self) -> TyAndLayout<'tcx> {
516 self.layout
517 }
518
519 #[inline]
520 fn meta(&self) -> MemPlaceMeta<Prov> {
521 match self.as_mplace_or_imm() {
522 Left(mplace) => mplace.meta(),
523 Right(_) => {
524 debug_assert!(self.layout.is_sized(), "unsized immediates are not a thing");
525 MemPlaceMeta::None
526 }
527 }
528 }
529
530 fn offset_with_meta<M: Machine<'tcx, Provenance = Prov>>(
531 &self,
532 offset: Size,
533 mode: OffsetMode,
534 meta: MemPlaceMeta<Prov>,
535 layout: TyAndLayout<'tcx>,
536 ecx: &InterpCx<'tcx, M>,
537 ) -> InterpResult<'tcx, Self> {
538 match self.as_mplace_or_imm() {
539 Left(mplace) => {
540 interp_ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into())
541 }
542 Right(imm) => {
543 assert_matches!(meta, MemPlaceMeta::None); interp_ok(imm.offset_(offset, layout, ecx).into())
546 }
547 }
548 }
549
550 #[inline(always)]
551 fn to_op<M: Machine<'tcx, Provenance = Prov>>(
552 &self,
553 _ecx: &InterpCx<'tcx, M>,
554 ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
555 interp_ok(self.clone())
556 }
557}
558
559impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
560 fn read_immediate_from_mplace_raw(
565 &self,
566 mplace: &MPlaceTy<'tcx, M::Provenance>,
567 ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::Provenance>>> {
568 if mplace.layout.is_unsized() {
569 return interp_ok(None);
571 }
572
573 let Some(alloc) = self.get_place_alloc(mplace)? else {
574 return interp_ok(Some(ImmTy::uninit(mplace.layout)));
576 };
577
578 interp_ok(match mplace.layout.backend_repr {
585 BackendRepr::Scalar(abi::Scalar::Initialized { value: s, .. }) => {
586 let size = s.size(self);
587 assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size");
588 let scalar = alloc.read_scalar(
589 alloc_range(Size::ZERO, size),
590 matches!(s, abi::Primitive::Pointer(_)),
591 )?;
592 Some(ImmTy::from_scalar(scalar, mplace.layout))
593 }
594 BackendRepr::ScalarPair(
595 abi::Scalar::Initialized { value: a, .. },
596 abi::Scalar::Initialized { value: b, .. },
597 ) => {
598 let (a_size, b_size) = (a.size(self), b.size(self));
602 let b_offset = a_size.align_to(b.align(self).abi);
603 assert!(b_offset.bytes() > 0); let a_val = alloc.read_scalar(
605 alloc_range(Size::ZERO, a_size),
606 matches!(a, abi::Primitive::Pointer(_)),
607 )?;
608 let b_val = alloc.read_scalar(
609 alloc_range(b_offset, b_size),
610 matches!(b, abi::Primitive::Pointer(_)),
611 )?;
612 Some(ImmTy::from_immediate(Immediate::ScalarPair(a_val, b_val), mplace.layout))
613 }
614 _ => {
615 None
617 }
618 })
619 }
620
621 pub fn read_immediate_raw(
630 &self,
631 src: &impl Projectable<'tcx, M::Provenance>,
632 ) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>> {
633 interp_ok(match src.to_op(self)?.as_mplace_or_imm() {
634 Left(ref mplace) => {
635 if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? {
636 Right(val)
637 } else {
638 Left(mplace.clone())
639 }
640 }
641 Right(val) => Right(val),
642 })
643 }
644
645 #[inline(always)]
649 pub fn read_immediate(
650 &self,
651 op: &impl Projectable<'tcx, M::Provenance>,
652 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
653 if !matches!(
654 op.layout().backend_repr,
655 BackendRepr::Scalar(abi::Scalar::Initialized { .. })
656 | BackendRepr::ScalarPair(
657 abi::Scalar::Initialized { .. },
658 abi::Scalar::Initialized { .. }
659 )
660 ) {
661 span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty);
662 }
663 let imm = self.read_immediate_raw(op)?.right().unwrap();
664 if matches!(*imm, Immediate::Uninit) {
665 throw_ub!(InvalidUninitBytes(None));
666 }
667 interp_ok(imm)
668 }
669
670 pub fn read_scalar(
672 &self,
673 op: &impl Projectable<'tcx, M::Provenance>,
674 ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
675 interp_ok(self.read_immediate(op)?.to_scalar())
676 }
677
678 pub fn read_pointer(
683 &self,
684 op: &impl Projectable<'tcx, M::Provenance>,
685 ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
686 self.read_scalar(op)?.to_pointer(self)
687 }
688 pub fn read_target_usize(
690 &self,
691 op: &impl Projectable<'tcx, M::Provenance>,
692 ) -> InterpResult<'tcx, u64> {
693 self.read_scalar(op)?.to_target_usize(self)
694 }
695 pub fn read_target_isize(
697 &self,
698 op: &impl Projectable<'tcx, M::Provenance>,
699 ) -> InterpResult<'tcx, i64> {
700 self.read_scalar(op)?.to_target_isize(self)
701 }
702
703 pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, &str> {
705 let len = mplace.len(self)?;
706 let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len))?;
707 let s = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
708 interp_ok(s)
709 }
710
711 pub fn local_to_op(
713 &self,
714 local: mir::Local,
715 layout: Option<TyAndLayout<'tcx>>,
716 ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
717 self.local_at_frame_to_op(self.frame(), local, layout)
718 }
719
720 pub fn local_at_frame_to_op(
726 &self,
727 frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
728 local: mir::Local,
729 layout: Option<TyAndLayout<'tcx>>,
730 ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
731 let layout = self.layout_of_local(frame, local, layout)?;
732 let op = *frame.locals[local].access()?;
733 if matches!(op, Operand::Immediate(_)) {
734 assert!(!layout.is_unsized());
735 }
736 M::after_local_read(self, frame, local)?;
737 interp_ok(OpTy { op, layout })
738 }
739
740 pub fn place_to_op(
744 &self,
745 place: &PlaceTy<'tcx, M::Provenance>,
746 ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
747 match place.as_mplace_or_local() {
748 Left(mplace) => interp_ok(mplace.into()),
749 Right((local, offset, locals_addr, _)) => {
750 debug_assert!(place.layout.is_sized()); debug_assert_eq!(locals_addr, self.frame().locals_addr());
752 let base = self.local_to_op(local, None)?;
753 interp_ok(match offset {
754 Some(offset) => base.offset(offset, place.layout, self)?,
755 None => {
756 debug_assert_eq!(place.layout, base.layout);
758 base
759 }
760 })
761 }
762 }
763 }
764
765 pub fn eval_place_to_op(
768 &self,
769 mir_place: mir::Place<'tcx>,
770 layout: Option<TyAndLayout<'tcx>>,
771 ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
772 let layout = if mir_place.projection.is_empty() { layout } else { None };
775
776 let mut op = self.local_to_op(mir_place.local, layout)?;
777 for elem in mir_place.projection.iter() {
779 op = self.project(&op, elem)?
780 }
781
782 trace!("eval_place_to_op: got {:?}", op);
783 if cfg!(debug_assertions) {
785 let normalized_place_ty = self
786 .instantiate_from_current_frame_and_normalize_erasing_regions(
787 mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
788 )?;
789 if !mir_assign_valid_types(
790 *self.tcx,
791 self.typing_env(),
792 self.layout_of(normalized_place_ty)?,
793 op.layout,
794 ) {
795 span_bug!(
796 self.cur_span(),
797 "eval_place of a MIR place with type {} produced an interpreter operand with type {}",
798 normalized_place_ty,
799 op.layout.ty,
800 )
801 }
802 }
803 interp_ok(op)
804 }
805
806 #[inline]
810 pub fn eval_operand(
811 &self,
812 mir_op: &mir::Operand<'tcx>,
813 layout: Option<TyAndLayout<'tcx>>,
814 ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
815 use rustc_middle::mir::Operand::*;
816 let op = match mir_op {
817 &Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?,
819
820 Constant(constant) => {
821 let c = self.instantiate_from_current_frame_and_normalize_erasing_regions(
822 constant.const_,
823 )?;
824
825 self.eval_mir_constant(&c, constant.span, layout)?
830 }
831 };
832 trace!("{:?}: {:?}", mir_op, op);
833 interp_ok(op)
834 }
835
836 pub(crate) fn const_val_to_op(
837 &self,
838 val_val: mir::ConstValue<'tcx>,
839 ty: Ty<'tcx>,
840 layout: Option<TyAndLayout<'tcx>>,
841 ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
842 let adjust_scalar = |scalar| -> InterpResult<'tcx, _> {
844 interp_ok(match scalar {
845 Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_root_pointer(ptr)?, size),
846 Scalar::Int(int) => Scalar::Int(int),
847 })
848 };
849 let layout =
850 from_known_layout(self.tcx, self.typing_env(), layout, || self.layout_of(ty).into())?;
851 let imm = match val_val {
852 mir::ConstValue::Indirect { alloc_id, offset } => {
853 let ptr = self.global_root_pointer(Pointer::new(
855 CtfeProvenance::from(alloc_id).as_immutable(),
856 offset,
857 ))?;
858 return interp_ok(self.ptr_to_mplace(ptr.into(), layout).into());
859 }
860 mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(),
861 mir::ConstValue::ZeroSized => Immediate::Uninit,
862 mir::ConstValue::Slice { data, meta } => {
863 let alloc_id = self.tcx.reserve_and_set_memory_alloc(data);
865 let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO);
866 Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self)
867 }
868 };
869 interp_ok(OpTy { op: Operand::Immediate(imm), layout })
870 }
871}
872
873#[cfg(target_pointer_width = "64")]
875mod size_asserts {
876 use rustc_data_structures::static_assert_size;
877
878 use super::*;
879 static_assert_size!(Immediate, 48);
881 static_assert_size!(ImmTy<'_>, 64);
882 static_assert_size!(Operand, 56);
883 static_assert_size!(OpTy<'_>, 72);
884 }