1use super::interpret::GlobalAlloc;
4use super::*;
5
6#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
11pub struct Statement<'tcx> {
12 pub source_info: SourceInfo,
13 pub kind: StatementKind<'tcx>,
14}
15
16impl Statement<'_> {
17 pub fn make_nop(&mut self) {
20 self.kind = StatementKind::Nop
21 }
22
23 #[must_use = "If you don't need the statement, use `make_nop` instead"]
25 pub fn replace_nop(&mut self) -> Self {
26 Statement {
27 source_info: self.source_info,
28 kind: mem::replace(&mut self.kind, StatementKind::Nop),
29 }
30 }
31}
32
33impl<'tcx> StatementKind<'tcx> {
34 pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> {
35 match self {
36 StatementKind::Assign(x) => Some(x),
37 _ => None,
38 }
39 }
40
41 pub fn as_assign(&self) -> Option<&(Place<'tcx>, Rvalue<'tcx>)> {
42 match self {
43 StatementKind::Assign(x) => Some(x),
44 _ => None,
45 }
46 }
47}
48
49impl<V, T> ProjectionElem<V, T> {
53 fn is_indirect(&self) -> bool {
56 match self {
57 Self::Deref => true,
58
59 Self::Field(_, _)
60 | Self::Index(_)
61 | Self::OpaqueCast(_)
62 | Self::Subtype(_)
63 | Self::ConstantIndex { .. }
64 | Self::Subslice { .. }
65 | Self::Downcast(_, _)
66 | Self::UnwrapUnsafeBinder(..) => false,
67 }
68 }
69
70 pub fn is_stable_offset(&self) -> bool {
73 match self {
74 Self::Deref | Self::Index(_) => false,
75 Self::Field(_, _)
76 | Self::OpaqueCast(_)
77 | Self::Subtype(_)
78 | Self::ConstantIndex { .. }
79 | Self::Subslice { .. }
80 | Self::Downcast(_, _)
81 | Self::UnwrapUnsafeBinder(..) => true,
82 }
83 }
84
85 pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
87 matches!(*self, Self::Downcast(_, x) if x == v)
88 }
89
90 pub fn is_field_to(&self, f: FieldIdx) -> bool {
92 matches!(*self, Self::Field(x, _) if x == f)
93 }
94
95 pub fn can_use_in_debuginfo(&self) -> bool {
97 match self {
98 Self::ConstantIndex { from_end: false, .. }
99 | Self::Deref
100 | Self::Downcast(_, _)
101 | Self::Field(_, _) => true,
102 Self::ConstantIndex { from_end: true, .. }
103 | Self::Index(_)
104 | Self::Subtype(_)
105 | Self::OpaqueCast(_)
106 | Self::Subslice { .. } => false,
107
108 Self::UnwrapUnsafeBinder(..) => false,
110 }
111 }
112}
113
114pub type ProjectionKind = ProjectionElem<(), ()>;
117
118#[derive(Clone, Copy, PartialEq, Eq, Hash)]
119pub struct PlaceRef<'tcx> {
120 pub local: Local,
121 pub projection: &'tcx [PlaceElem<'tcx>],
122}
123
124impl<'tcx> !PartialOrd for PlaceRef<'tcx> {}
129
130impl<'tcx> Place<'tcx> {
131 pub fn return_place() -> Place<'tcx> {
133 Place { local: RETURN_PLACE, projection: List::empty() }
134 }
135
136 pub fn is_indirect(&self) -> bool {
141 self.projection.iter().any(|elem| elem.is_indirect())
142 }
143
144 pub fn is_indirect_first_projection(&self) -> bool {
150 self.as_ref().is_indirect_first_projection()
151 }
152
153 #[inline(always)]
156 pub fn local_or_deref_local(&self) -> Option<Local> {
157 self.as_ref().local_or_deref_local()
158 }
159
160 #[inline(always)]
163 pub fn as_local(&self) -> Option<Local> {
164 self.as_ref().as_local()
165 }
166
167 #[inline]
168 pub fn as_ref(&self) -> PlaceRef<'tcx> {
169 PlaceRef { local: self.local, projection: self.projection }
170 }
171
172 #[inline]
180 pub fn iter_projections(
181 self,
182 ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
183 self.as_ref().iter_projections()
184 }
185
186 pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self {
189 if more_projections.is_empty() {
190 return self;
191 }
192
193 self.as_ref().project_deeper(more_projections, tcx)
194 }
195}
196
197impl From<Local> for Place<'_> {
198 #[inline]
199 fn from(local: Local) -> Self {
200 Place { local, projection: List::empty() }
201 }
202}
203
204impl<'tcx> PlaceRef<'tcx> {
205 pub fn local_or_deref_local(&self) -> Option<Local> {
208 match *self {
209 PlaceRef { local, projection: [] }
210 | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
211 _ => None,
212 }
213 }
214
215 pub fn is_indirect(&self) -> bool {
220 self.projection.iter().any(|elem| elem.is_indirect())
221 }
222
223 pub fn is_indirect_first_projection(&self) -> bool {
229 debug_assert!(
231 self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
232 );
233 self.projection.first() == Some(&PlaceElem::Deref)
234 }
235
236 #[inline]
239 pub fn as_local(&self) -> Option<Local> {
240 match *self {
241 PlaceRef { local, projection: [] } => Some(local),
242 _ => None,
243 }
244 }
245
246 #[inline]
247 pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
248 Place { local: self.local, projection: tcx.mk_place_elems(self.projection) }
249 }
250
251 #[inline]
252 pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
253 if let &[ref proj_base @ .., elem] = self.projection {
254 Some((PlaceRef { local: self.local, projection: proj_base }, elem))
255 } else {
256 None
257 }
258 }
259
260 #[inline]
268 pub fn iter_projections(
269 self,
270 ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
271 self.projection.iter().enumerate().map(move |(i, proj)| {
272 let base = PlaceRef { local: self.local, projection: &self.projection[..i] };
273 (base, *proj)
274 })
275 }
276
277 pub fn project_deeper(
280 self,
281 more_projections: &[PlaceElem<'tcx>],
282 tcx: TyCtxt<'tcx>,
283 ) -> Place<'tcx> {
284 let mut v: Vec<PlaceElem<'tcx>>;
285
286 let new_projections = if self.projection.is_empty() {
287 more_projections
288 } else {
289 v = Vec::with_capacity(self.projection.len() + more_projections.len());
290 v.extend(self.projection);
291 v.extend(more_projections);
292 &v
293 };
294
295 Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
296 }
297}
298
299impl From<Local> for PlaceRef<'_> {
300 #[inline]
301 fn from(local: Local) -> Self {
302 PlaceRef { local, projection: &[] }
303 }
304}
305
306impl<'tcx> Operand<'tcx> {
310 pub fn function_handle(
314 tcx: TyCtxt<'tcx>,
315 def_id: DefId,
316 args: impl IntoIterator<Item = GenericArg<'tcx>>,
317 span: Span,
318 ) -> Self {
319 let ty = Ty::new_fn_def(tcx, def_id, args);
320 Operand::Constant(Box::new(ConstOperand {
321 span,
322 user_ty: None,
323 const_: Const::Val(ConstValue::ZeroSized, ty),
324 }))
325 }
326
327 pub fn is_move(&self) -> bool {
328 matches!(self, Operand::Move(..))
329 }
330
331 pub fn const_from_scalar(
334 tcx: TyCtxt<'tcx>,
335 ty: Ty<'tcx>,
336 val: Scalar,
337 span: Span,
338 ) -> Operand<'tcx> {
339 debug_assert!({
340 let typing_env = ty::TypingEnv::fully_monomorphized();
341 let type_size = tcx
342 .layout_of(typing_env.as_query_input(ty))
343 .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
344 .size;
345 let scalar_size = match val {
346 Scalar::Int(int) => int.size(),
347 _ => panic!("Invalid scalar type {val:?}"),
348 };
349 scalar_size == type_size
350 });
351 Operand::Constant(Box::new(ConstOperand {
352 span,
353 user_ty: None,
354 const_: Const::Val(ConstValue::Scalar(val), ty),
355 }))
356 }
357
358 pub fn to_copy(&self) -> Self {
359 match *self {
360 Operand::Copy(_) | Operand::Constant(_) => self.clone(),
361 Operand::Move(place) => Operand::Copy(place),
362 }
363 }
364
365 pub fn place(&self) -> Option<Place<'tcx>> {
368 match self {
369 Operand::Copy(place) | Operand::Move(place) => Some(*place),
370 Operand::Constant(_) => None,
371 }
372 }
373
374 pub fn constant(&self) -> Option<&ConstOperand<'tcx>> {
377 match self {
378 Operand::Constant(x) => Some(&**x),
379 Operand::Copy(_) | Operand::Move(_) => None,
380 }
381 }
382
383 pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
388 let const_ty = self.constant()?.const_.ty();
389 if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
390 }
391}
392
393impl<'tcx> ConstOperand<'tcx> {
394 pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
395 match self.const_.try_to_scalar() {
396 Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance.alloc_id()) {
397 GlobalAlloc::Static(def_id) => {
398 assert!(!tcx.is_thread_local_static(def_id));
399 Some(def_id)
400 }
401 _ => None,
402 },
403 _ => None,
404 }
405 }
406
407 #[inline]
408 pub fn ty(&self) -> Ty<'tcx> {
409 self.const_.ty()
410 }
411}
412
413impl<'tcx> Rvalue<'tcx> {
417 #[inline]
419 pub fn is_safe_to_remove(&self) -> bool {
420 match self {
421 Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => false,
425
426 Rvalue::Use(_)
427 | Rvalue::CopyForDeref(_)
428 | Rvalue::Repeat(_, _)
429 | Rvalue::Ref(_, _, _)
430 | Rvalue::ThreadLocalRef(_)
431 | Rvalue::RawPtr(_, _)
432 | Rvalue::Len(_)
433 | Rvalue::Cast(
434 CastKind::IntToInt
435 | CastKind::FloatToInt
436 | CastKind::FloatToFloat
437 | CastKind::IntToFloat
438 | CastKind::FnPtrToPtr
439 | CastKind::PtrToPtr
440 | CastKind::PointerCoercion(_, _)
441 | CastKind::PointerWithExposedProvenance
442 | CastKind::Transmute,
443 _,
444 _,
445 )
446 | Rvalue::BinaryOp(_, _)
447 | Rvalue::NullaryOp(_, _)
448 | Rvalue::UnaryOp(_, _)
449 | Rvalue::Discriminant(_)
450 | Rvalue::Aggregate(_, _)
451 | Rvalue::ShallowInitBox(_, _)
452 | Rvalue::WrapUnsafeBinder(_, _) => true,
453 }
454 }
455}
456
457impl BorrowKind {
458 pub fn mutability(&self) -> Mutability {
459 match *self {
460 BorrowKind::Shared | BorrowKind::Fake(_) => Mutability::Not,
461 BorrowKind::Mut { .. } => Mutability::Mut,
462 }
463 }
464
465 pub fn allows_two_phase_borrow(&self) -> bool {
468 match *self {
469 BorrowKind::Shared
470 | BorrowKind::Fake(_)
471 | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
472 false
473 }
474 BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true,
475 }
476 }
477}