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