• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! MIR definitions and implementation
2 
3 use std::{fmt::Display, iter};
4 
5 use crate::{
6     consteval::usize_const, db::HirDatabase, display::HirDisplay, infer::PointerCast,
7     lang_items::is_box, mapping::ToChalk, CallableDefId, ClosureId, Const, ConstScalar,
8     InferenceResult, Interner, MemoryMap, Substitution, Ty, TyKind,
9 };
10 use base_db::CrateId;
11 use chalk_ir::Mutability;
12 use hir_def::{
13     hir::{BindingId, Expr, ExprId, Ordering, PatId},
14     DefWithBodyId, FieldId, StaticId, UnionId, VariantId,
15 };
16 use la_arena::{Arena, ArenaMap, Idx, RawIdx};
17 
18 mod eval;
19 mod lower;
20 mod borrowck;
21 mod pretty;
22 mod monomorphization;
23 
24 pub use borrowck::{borrowck_query, BorrowckResult, MutabilityReason};
25 pub use eval::{interpret_mir, pad16, Evaluator, MirEvalError, VTableMap};
26 pub use lower::{
27     lower_to_mir, mir_body_for_closure_query, mir_body_query, mir_body_recover, MirLowerError,
28 };
29 pub use monomorphization::{
30     monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query,
31     monomorphized_mir_body_query, monomorphized_mir_body_recover,
32 };
33 use smallvec::{smallvec, SmallVec};
34 use stdx::{impl_from, never};
35 
36 use super::consteval::{intern_const_scalar, try_const_usize};
37 
38 pub type BasicBlockId = Idx<BasicBlock>;
39 pub type LocalId = Idx<Local>;
40 
return_slot() -> LocalId41 fn return_slot() -> LocalId {
42     LocalId::from_raw(RawIdx::from(0))
43 }
44 
45 #[derive(Debug, Clone, PartialEq, Eq)]
46 pub struct Local {
47     pub ty: Ty,
48 }
49 
50 /// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of
51 /// the memory model. One proposal for a definition of values can be found [on UCG][value-def].
52 ///
53 /// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md
54 ///
55 /// The most common way to create values is via loading a place. Loading a place is an operation
56 /// which reads the memory of the place and converts it to a value. This is a fundamentally *typed*
57 /// operation. The nature of the value produced depends on the type of the conversion. Furthermore,
58 /// there may be other effects: if the type has a validity constraint loading the place might be UB
59 /// if the validity constraint is not met.
60 ///
61 /// **Needs clarification:** Ralf proposes that loading a place not have side-effects.
62 /// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this
63 /// something we can even decide without knowing more about Rust's memory model?
64 ///
65 /// **Needs clarification:** Is loading a place that has its variant index set well-formed? Miri
66 /// currently implements it, but it seems like this may be something to check against in the
67 /// validator.
68 #[derive(Debug, PartialEq, Eq, Clone)]
69 pub enum Operand {
70     /// Creates a value by loading the given place.
71     ///
72     /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there
73     /// is no such requirement.
74     Copy(Place),
75 
76     /// Creates a value by performing loading the place, just like the `Copy` operand.
77     ///
78     /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide
79     /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this
80     /// place without first re-initializing it.
81     ///
82     /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188
83     Move(Place),
84     /// Constants are already semantically values, and remain unchanged.
85     Constant(Const),
86     /// NON STANDARD: This kind of operand returns an immutable reference to that static memory. Rustc
87     /// handles it with the `Constant` variant somehow.
88     Static(StaticId),
89 }
90 
91 impl Operand {
from_concrete_const(data: Vec<u8>, memory_map: MemoryMap, ty: Ty) -> Self92     fn from_concrete_const(data: Vec<u8>, memory_map: MemoryMap, ty: Ty) -> Self {
93         Operand::Constant(intern_const_scalar(ConstScalar::Bytes(data, memory_map), ty))
94     }
95 
from_bytes(data: Vec<u8>, ty: Ty) -> Self96     fn from_bytes(data: Vec<u8>, ty: Ty) -> Self {
97         Operand::from_concrete_const(data, MemoryMap::default(), ty)
98     }
99 
const_zst(ty: Ty) -> Operand100     fn const_zst(ty: Ty) -> Operand {
101         Self::from_bytes(vec![], ty)
102     }
103 
from_fn( db: &dyn HirDatabase, func_id: hir_def::FunctionId, generic_args: Substitution, ) -> Operand104     fn from_fn(
105         db: &dyn HirDatabase,
106         func_id: hir_def::FunctionId,
107         generic_args: Substitution,
108     ) -> Operand {
109         let ty =
110             chalk_ir::TyKind::FnDef(CallableDefId::FunctionId(func_id).to_chalk(db), generic_args)
111                 .intern(Interner);
112         Operand::from_bytes(vec![], ty)
113     }
114 }
115 
116 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
117 pub enum ProjectionElem<V, T> {
118     Deref,
119     Field(FieldId),
120     // FIXME: get rid of this, and use FieldId for tuples and closures
121     TupleOrClosureField(usize),
122     Index(V),
123     ConstantIndex { offset: u64, from_end: bool },
124     Subslice { from: u64, to: u64 },
125     //Downcast(Option<Symbol>, VariantIdx),
126     OpaqueCast(T),
127 }
128 
129 impl<V, T> ProjectionElem<V, T> {
projected_ty( &self, base: Ty, db: &dyn HirDatabase, closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty, krate: CrateId, ) -> Ty130     pub fn projected_ty(
131         &self,
132         base: Ty,
133         db: &dyn HirDatabase,
134         closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty,
135         krate: CrateId,
136     ) -> Ty {
137         match self {
138             ProjectionElem::Deref => match &base.data(Interner).kind {
139                 TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(),
140                 TyKind::Adt(adt, subst) if is_box(db, adt.0) => {
141                     subst.at(Interner, 0).assert_ty_ref(Interner).clone()
142                 }
143                 _ => {
144                     never!("Overloaded deref on type {} is not a projection", base.display(db));
145                     return TyKind::Error.intern(Interner);
146                 }
147             },
148             ProjectionElem::Field(f) => match &base.data(Interner).kind {
149                 TyKind::Adt(_, subst) => {
150                     db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
151                 }
152                 _ => {
153                     never!("Only adt has field");
154                     return TyKind::Error.intern(Interner);
155                 }
156             },
157             ProjectionElem::TupleOrClosureField(f) => match &base.data(Interner).kind {
158                 TyKind::Tuple(_, subst) => subst
159                     .as_slice(Interner)
160                     .get(*f)
161                     .map(|x| x.assert_ty_ref(Interner))
162                     .cloned()
163                     .unwrap_or_else(|| {
164                         never!("Out of bound tuple field");
165                         TyKind::Error.intern(Interner)
166                     }),
167                 TyKind::Closure(id, subst) => closure_field(*id, subst, *f),
168                 _ => {
169                     never!("Only tuple or closure has tuple or closure field");
170                     return TyKind::Error.intern(Interner);
171                 }
172             },
173             ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => {
174                 match &base.data(Interner).kind {
175                     TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
176                     _ => {
177                         never!("Overloaded index is not a projection");
178                         return TyKind::Error.intern(Interner);
179                     }
180                 }
181             }
182             &ProjectionElem::Subslice { from, to } => match &base.data(Interner).kind {
183                 TyKind::Array(inner, c) => {
184                     let next_c = usize_const(
185                         db,
186                         match try_const_usize(db, c) {
187                             None => None,
188                             Some(x) => x.checked_sub(u128::from(from + to)),
189                         },
190                         krate,
191                     );
192                     TyKind::Array(inner.clone(), next_c).intern(Interner)
193                 }
194                 TyKind::Slice(_) => base.clone(),
195                 _ => {
196                     never!("Subslice projection should only happen on slice and array");
197                     return TyKind::Error.intern(Interner);
198                 }
199             },
200             ProjectionElem::OpaqueCast(_) => {
201                 never!("We don't emit these yet");
202                 return TyKind::Error.intern(Interner);
203             }
204         }
205     }
206 }
207 
208 type PlaceElem = ProjectionElem<LocalId, Ty>;
209 
210 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
211 pub struct Place {
212     pub local: LocalId,
213     pub projection: Box<[PlaceElem]>,
214 }
215 
216 impl Place {
is_parent(&self, child: &Place) -> bool217     fn is_parent(&self, child: &Place) -> bool {
218         self.local == child.local && child.projection.starts_with(&self.projection)
219     }
220 
iterate_over_parents(&self) -> impl Iterator<Item = Place> + '_221     fn iterate_over_parents(&self) -> impl Iterator<Item = Place> + '_ {
222         (0..self.projection.len())
223             .map(|x| &self.projection[0..x])
224             .map(|x| Place { local: self.local, projection: x.to_vec().into() })
225     }
226 
project(&self, projection: PlaceElem) -> Place227     fn project(&self, projection: PlaceElem) -> Place {
228         Place {
229             local: self.local,
230             projection: self.projection.iter().cloned().chain([projection]).collect(),
231         }
232     }
233 }
234 
235 impl From<LocalId> for Place {
from(local: LocalId) -> Self236     fn from(local: LocalId) -> Self {
237         Self { local, projection: vec![].into() }
238     }
239 }
240 
241 #[derive(Debug, PartialEq, Eq, Clone)]
242 pub enum AggregateKind {
243     /// The type is of the element
244     Array(Ty),
245     /// The type is of the tuple
246     Tuple(Ty),
247     Adt(VariantId, Substitution),
248     Union(UnionId, FieldId),
249     Closure(Ty),
250     //Generator(LocalDefId, SubstsRef, Movability),
251 }
252 
253 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
254 pub struct SwitchTargets {
255     /// Possible values. The locations to branch to in each case
256     /// are found in the corresponding indices from the `targets` vector.
257     values: SmallVec<[u128; 1]>,
258 
259     /// Possible branch sites. The last element of this vector is used
260     /// for the otherwise branch, so targets.len() == values.len() + 1
261     /// should hold.
262     //
263     // This invariant is quite non-obvious and also could be improved.
264     // One way to make this invariant is to have something like this instead:
265     //
266     // branches: Vec<(ConstInt, BasicBlock)>,
267     // otherwise: Option<BasicBlock> // exhaustive if None
268     //
269     // However we’ve decided to keep this as-is until we figure a case
270     // where some other approach seems to be strictly better than other.
271     targets: SmallVec<[BasicBlockId; 2]>,
272 }
273 
274 impl SwitchTargets {
275     /// Creates switch targets from an iterator of values and target blocks.
276     ///
277     /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to
278     /// `goto otherwise;`.
new( targets: impl Iterator<Item = (u128, BasicBlockId)>, otherwise: BasicBlockId, ) -> Self279     pub fn new(
280         targets: impl Iterator<Item = (u128, BasicBlockId)>,
281         otherwise: BasicBlockId,
282     ) -> Self {
283         let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip();
284         targets.push(otherwise);
285         Self { values, targets }
286     }
287 
288     /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`,
289     /// and to `else_` if not.
static_if(value: u128, then: BasicBlockId, else_: BasicBlockId) -> Self290     pub fn static_if(value: u128, then: BasicBlockId, else_: BasicBlockId) -> Self {
291         Self { values: smallvec![value], targets: smallvec![then, else_] }
292     }
293 
294     /// Returns the fallback target that is jumped to when none of the values match the operand.
otherwise(&self) -> BasicBlockId295     pub fn otherwise(&self) -> BasicBlockId {
296         *self.targets.last().unwrap()
297     }
298 
299     /// Returns an iterator over the switch targets.
300     ///
301     /// The iterator will yield tuples containing the value and corresponding target to jump to, not
302     /// including the `otherwise` fallback target.
303     ///
304     /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory.
iter(&self) -> impl Iterator<Item = (u128, BasicBlockId)> + '_305     pub fn iter(&self) -> impl Iterator<Item = (u128, BasicBlockId)> + '_ {
306         iter::zip(&self.values, &self.targets).map(|(x, y)| (*x, *y))
307     }
308 
309     /// Returns a slice with all possible jump targets (including the fallback target).
all_targets(&self) -> &[BasicBlockId]310     pub fn all_targets(&self) -> &[BasicBlockId] {
311         &self.targets
312     }
313 
314     /// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
315     /// specific value. This cannot fail, as it'll return the `otherwise`
316     /// branch if there's not a specific match for the value.
target_for_value(&self, value: u128) -> BasicBlockId317     pub fn target_for_value(&self, value: u128) -> BasicBlockId {
318         self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
319     }
320 }
321 
322 #[derive(Debug, PartialEq, Eq, Clone)]
323 pub struct Terminator {
324     span: MirSpan,
325     kind: TerminatorKind,
326 }
327 
328 #[derive(Debug, PartialEq, Eq, Clone)]
329 pub enum TerminatorKind {
330     /// Block has one successor; we continue execution there.
331     Goto { target: BasicBlockId },
332 
333     /// Switches based on the computed value.
334     ///
335     /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned
336     /// integer, char, or bool, and must match the given type. Then, if the list of switch targets
337     /// contains the computed value, continues execution at the associated basic block. Otherwise,
338     /// continues execution at the "otherwise" basic block.
339     ///
340     /// Target values may not appear more than once.
341     SwitchInt {
342         /// The discriminant value being tested.
343         discr: Operand,
344 
345         targets: SwitchTargets,
346     },
347 
348     /// Indicates that the landing pad is finished and that the process should continue unwinding.
349     ///
350     /// Like a return, this marks the end of this invocation of the function.
351     ///
352     /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after
353     /// deaggregation runs.
354     Resume,
355 
356     /// Indicates that the landing pad is finished and that the process should abort.
357     ///
358     /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
359     /// cleanup blocks.
360     Abort,
361 
362     /// Returns from the function.
363     ///
364     /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very
365     /// likely at least assigns the value currently in the return place (`_0`) to the place
366     /// specified in the associated `Call` terminator in the calling function, as if assigned via
367     /// `dest = move _0`. It might additionally do other things, like have side-effects in the
368     /// aliasing model.
369     ///
370     /// If the body is a generator body, this has slightly different semantics; it instead causes a
371     /// `GeneratorState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned
372     /// to the return place.
373     Return,
374 
375     /// Indicates a terminator that can never be reached.
376     ///
377     /// Executing this terminator is UB.
378     Unreachable,
379 
380     /// The behavior of this statement differs significantly before and after drop elaboration.
381     /// After drop elaboration, `Drop` executes the drop glue for the specified place, after which
382     /// it continues execution/unwinds at the given basic blocks. It is possible that executing drop
383     /// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an
384     /// issue tracking if drop glue has any interesting semantics in addition to those of a function
385     /// call?)
386     ///
387     /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the
388     /// `Drop` will be executed if...
389     ///
390     /// **Needs clarification**: End of that sentence. This in effect should document the exact
391     /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure:
392     ///
393     /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
394     /// > the place or one of its "parents" occurred more recently than a move out of it. This does not
395     /// > consider indirect assignments.
396     Drop { place: Place, target: BasicBlockId, unwind: Option<BasicBlockId> },
397 
398     /// Drops the place and assigns a new value to it.
399     ///
400     /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator;
401     /// it then additionally assigns the `value` to the `place` as if by an assignment statement.
402     /// This assignment occurs both in the unwind and the regular code paths. The semantics are best
403     /// explained by the elaboration:
404     ///
405     /// ```ignore (MIR)
406     /// BB0 {
407     ///   DropAndReplace(P <- V, goto BB1, unwind BB2)
408     /// }
409     /// ```
410     ///
411     /// becomes
412     ///
413     /// ```ignore (MIR)
414     /// BB0 {
415     ///   Drop(P, goto BB1, unwind BB2)
416     /// }
417     /// BB1 {
418     ///   // P is now uninitialized
419     ///   P <- V
420     /// }
421     /// BB2 {
422     ///   // P is now uninitialized -- its dtor panicked
423     ///   P <- V
424     /// }
425     /// ```
426     ///
427     /// Disallowed after drop elaboration.
428     DropAndReplace {
429         place: Place,
430         value: Operand,
431         target: BasicBlockId,
432         unwind: Option<BasicBlockId>,
433     },
434 
435     /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
436     /// the referred to function. The operand types must match the argument types of the function.
437     /// The return place type must match the return type. The type of the `func` operand must be
438     /// callable, meaning either a function pointer, a function type, or a closure type.
439     ///
440     /// **Needs clarification**: The exact semantics of this. Current backends rely on `move`
441     /// operands not aliasing the return place. It is unclear how this is justified in MIR, see
442     /// [#71117].
443     ///
444     /// [#71117]: https://github.com/rust-lang/rust/issues/71117
445     Call {
446         /// The function that’s being called.
447         func: Operand,
448         /// Arguments the function is called with.
449         /// These are owned by the callee, which is free to modify them.
450         /// This allows the memory occupied by "by-value" arguments to be
451         /// reused across function calls without duplicating the contents.
452         args: Box<[Operand]>,
453         /// Where the returned value will be written
454         destination: Place,
455         /// Where to go after this call returns. If none, the call necessarily diverges.
456         target: Option<BasicBlockId>,
457         /// Cleanups to be done if the call unwinds.
458         cleanup: Option<BasicBlockId>,
459         /// `true` if this is from a call in HIR rather than from an overloaded
460         /// operator. True for overloaded function call.
461         from_hir_call: bool,
462         // This `Span` is the span of the function, without the dot and receiver
463         // (e.g. `foo(a, b)` in `x.foo(a, b)`
464         //fn_span: Span,
465     },
466 
467     /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`,
468     /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some
469     /// unspecified constant as the function to call, all the operands stored in the `AssertMessage`
470     /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not
471     /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the
472     /// assertion does not fail, execution continues at the specified basic block.
473     Assert {
474         cond: Operand,
475         expected: bool,
476         //msg: AssertMessage,
477         target: BasicBlockId,
478         cleanup: Option<BasicBlockId>,
479     },
480 
481     /// Marks a suspend point.
482     ///
483     /// Like `Return` terminators in generator bodies, this computes `value` and then a
484     /// `GeneratorState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to
485     /// the return place of the function calling this one, and execution continues in the calling
486     /// function. When next invoked with the same first argument, execution of this function
487     /// continues at the `resume` basic block, with the second argument written to the `resume_arg`
488     /// place. If the generator is dropped before then, the `drop` basic block is invoked.
489     ///
490     /// Not permitted in bodies that are not generator bodies, or after generator lowering.
491     ///
492     /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`?
493     Yield {
494         /// The value to return.
495         value: Operand,
496         /// Where to resume to.
497         resume: BasicBlockId,
498         /// The place to store the resume argument in.
499         resume_arg: Place,
500         /// Cleanup to be done if the generator is dropped at this suspend point.
501         drop: Option<BasicBlockId>,
502     },
503 
504     /// Indicates the end of dropping a generator.
505     ///
506     /// Semantically just a `return` (from the generators drop glue). Only permitted in the same situations
507     /// as `yield`.
508     ///
509     /// **Needs clarification**: Is that even correct? The generator drop code is always confusing
510     /// to me, because it's not even really in the current body.
511     ///
512     /// **Needs clarification**: Are there type system constraints on these terminators? Should
513     /// there be a "block type" like `cleanup` blocks for them?
514     GeneratorDrop,
515 
516     /// A block where control flow only ever takes one real path, but borrowck needs to be more
517     /// conservative.
518     ///
519     /// At runtime this is semantically just a goto.
520     ///
521     /// Disallowed after drop elaboration.
522     FalseEdge {
523         /// The target normal control flow will take.
524         real_target: BasicBlockId,
525         /// A block control flow could conceptually jump to, but won't in
526         /// practice.
527         imaginary_target: BasicBlockId,
528     },
529 
530     /// A terminator for blocks that only take one path in reality, but where we reserve the right
531     /// to unwind in borrowck, even if it won't happen in practice. This can arise in infinite loops
532     /// with no function calls for example.
533     ///
534     /// At runtime this is semantically just a goto.
535     ///
536     /// Disallowed after drop elaboration.
537     FalseUnwind {
538         /// The target normal control flow will take.
539         real_target: BasicBlockId,
540         /// The imaginary cleanup block link. This particular path will never be taken
541         /// in practice, but in order to avoid fragility we want to always
542         /// consider it in borrowck. We don't want to accept programs which
543         /// pass borrowck only when `panic=abort` or some assertions are disabled
544         /// due to release vs. debug mode builds. This needs to be an `Option` because
545         /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes.
546         unwind: Option<BasicBlockId>,
547     },
548 }
549 
550 #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
551 pub enum BorrowKind {
552     /// Data must be immutable and is aliasable.
553     Shared,
554 
555     /// The immediately borrowed place must be immutable, but projections from
556     /// it don't need to be. For example, a shallow borrow of `a.b` doesn't
557     /// conflict with a mutable borrow of `a.b.c`.
558     ///
559     /// This is used when lowering matches: when matching on a place we want to
560     /// ensure that place have the same value from the start of the match until
561     /// an arm is selected. This prevents this code from compiling:
562     /// ```compile_fail,E0510
563     /// let mut x = &Some(0);
564     /// match *x {
565     ///     None => (),
566     ///     Some(_) if { x = &None; false } => (),
567     ///     Some(_) => (),
568     /// }
569     /// ```
570     /// This can't be a shared borrow because mutably borrowing (*x as Some).0
571     /// should not prevent `if let None = x { ... }`, for example, because the
572     /// mutating `(*x as Some).0` can't affect the discriminant of `x`.
573     /// We can also report errors with this kind of borrow differently.
574     Shallow,
575 
576     /// Data must be immutable but not aliasable. This kind of borrow
577     /// cannot currently be expressed by the user and is used only in
578     /// implicit closure bindings. It is needed when the closure is
579     /// borrowing or mutating a mutable referent, e.g.:
580     /// ```
581     /// let mut z = 3;
582     /// let x: &mut isize = &mut z;
583     /// let y = || *x += 5;
584     /// ```
585     /// If we were to try to translate this closure into a more explicit
586     /// form, we'd encounter an error with the code as written:
587     /// ```compile_fail,E0594
588     /// struct Env<'a> { x: &'a &'a mut isize }
589     /// let mut z = 3;
590     /// let x: &mut isize = &mut z;
591     /// let y = (&mut Env { x: &x }, fn_ptr);  // Closure is pair of env and fn
592     /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
593     /// ```
594     /// This is then illegal because you cannot mutate an `&mut` found
595     /// in an aliasable location. To solve, you'd have to translate with
596     /// an `&mut` borrow:
597     /// ```compile_fail,E0596
598     /// struct Env<'a> { x: &'a mut &'a mut isize }
599     /// let mut z = 3;
600     /// let x: &mut isize = &mut z;
601     /// let y = (&mut Env { x: &mut x }, fn_ptr); // changed from &x to &mut x
602     /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
603     /// ```
604     /// Now the assignment to `**env.x` is legal, but creating a
605     /// mutable pointer to `x` is not because `x` is not mutable. We
606     /// could fix this by declaring `x` as `let mut x`. This is ok in
607     /// user code, if awkward, but extra weird for closures, since the
608     /// borrow is hidden.
609     ///
610     /// So we introduce a "unique imm" borrow -- the referent is
611     /// immutable, but not aliasable. This solves the problem. For
612     /// simplicity, we don't give users the way to express this
613     /// borrow, it's just used when translating closures.
614     Unique,
615 
616     /// Data is mutable and not aliasable.
617     Mut {
618         /// `true` if this borrow arose from method-call auto-ref
619         /// (i.e., `adjustment::Adjust::Borrow`).
620         allow_two_phase_borrow: bool,
621     },
622 }
623 
624 impl BorrowKind {
from_hir(m: hir_def::type_ref::Mutability) -> Self625     fn from_hir(m: hir_def::type_ref::Mutability) -> Self {
626         match m {
627             hir_def::type_ref::Mutability::Shared => BorrowKind::Shared,
628             hir_def::type_ref::Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
629         }
630     }
631 
from_chalk(m: Mutability) -> Self632     fn from_chalk(m: Mutability) -> Self {
633         match m {
634             Mutability::Not => BorrowKind::Shared,
635             Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
636         }
637     }
638 }
639 
640 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
641 pub enum UnOp {
642     /// The `!` operator for logical inversion
643     Not,
644     /// The `-` operator for negation
645     Neg,
646 }
647 
648 #[derive(Debug, PartialEq, Eq, Clone)]
649 pub enum BinOp {
650     /// The `+` operator (addition)
651     Add,
652     /// The `-` operator (subtraction)
653     Sub,
654     /// The `*` operator (multiplication)
655     Mul,
656     /// The `/` operator (division)
657     ///
658     /// Division by zero is UB, because the compiler should have inserted checks
659     /// prior to this.
660     Div,
661     /// The `%` operator (modulus)
662     ///
663     /// Using zero as the modulus (second operand) is UB, because the compiler
664     /// should have inserted checks prior to this.
665     Rem,
666     /// The `^` operator (bitwise xor)
667     BitXor,
668     /// The `&` operator (bitwise and)
669     BitAnd,
670     /// The `|` operator (bitwise or)
671     BitOr,
672     /// The `<<` operator (shift left)
673     ///
674     /// The offset is truncated to the size of the first operand before shifting.
675     Shl,
676     /// The `>>` operator (shift right)
677     ///
678     /// The offset is truncated to the size of the first operand before shifting.
679     Shr,
680     /// The `==` operator (equality)
681     Eq,
682     /// The `<` operator (less than)
683     Lt,
684     /// The `<=` operator (less than or equal to)
685     Le,
686     /// The `!=` operator (not equal to)
687     Ne,
688     /// The `>=` operator (greater than or equal to)
689     Ge,
690     /// The `>` operator (greater than)
691     Gt,
692     /// The `ptr.offset` operator
693     Offset,
694 }
695 
696 impl BinOp {
run_compare<T: PartialEq + PartialOrd>(&self, l: T, r: T) -> bool697     fn run_compare<T: PartialEq + PartialOrd>(&self, l: T, r: T) -> bool {
698         match self {
699             BinOp::Ge => l >= r,
700             BinOp::Gt => l > r,
701             BinOp::Le => l <= r,
702             BinOp::Lt => l < r,
703             BinOp::Eq => l == r,
704             BinOp::Ne => l != r,
705             x => panic!("`run_compare` called on operator {x:?}"),
706         }
707     }
708 }
709 
710 impl Display for BinOp {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result711     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
712         f.write_str(match self {
713             BinOp::Add => "+",
714             BinOp::Sub => "-",
715             BinOp::Mul => "*",
716             BinOp::Div => "/",
717             BinOp::Rem => "%",
718             BinOp::BitXor => "^",
719             BinOp::BitAnd => "&",
720             BinOp::BitOr => "|",
721             BinOp::Shl => "<<",
722             BinOp::Shr => ">>",
723             BinOp::Eq => "==",
724             BinOp::Lt => "<",
725             BinOp::Le => "<=",
726             BinOp::Ne => "!=",
727             BinOp::Ge => ">=",
728             BinOp::Gt => ">",
729             BinOp::Offset => "`offset`",
730         })
731     }
732 }
733 
734 impl From<hir_def::hir::ArithOp> for BinOp {
from(value: hir_def::hir::ArithOp) -> Self735     fn from(value: hir_def::hir::ArithOp) -> Self {
736         match value {
737             hir_def::hir::ArithOp::Add => BinOp::Add,
738             hir_def::hir::ArithOp::Mul => BinOp::Mul,
739             hir_def::hir::ArithOp::Sub => BinOp::Sub,
740             hir_def::hir::ArithOp::Div => BinOp::Div,
741             hir_def::hir::ArithOp::Rem => BinOp::Rem,
742             hir_def::hir::ArithOp::Shl => BinOp::Shl,
743             hir_def::hir::ArithOp::Shr => BinOp::Shr,
744             hir_def::hir::ArithOp::BitXor => BinOp::BitXor,
745             hir_def::hir::ArithOp::BitOr => BinOp::BitOr,
746             hir_def::hir::ArithOp::BitAnd => BinOp::BitAnd,
747         }
748     }
749 }
750 
751 impl From<hir_def::hir::CmpOp> for BinOp {
from(value: hir_def::hir::CmpOp) -> Self752     fn from(value: hir_def::hir::CmpOp) -> Self {
753         match value {
754             hir_def::hir::CmpOp::Eq { negated: false } => BinOp::Eq,
755             hir_def::hir::CmpOp::Eq { negated: true } => BinOp::Ne,
756             hir_def::hir::CmpOp::Ord { ordering: Ordering::Greater, strict: false } => BinOp::Ge,
757             hir_def::hir::CmpOp::Ord { ordering: Ordering::Greater, strict: true } => BinOp::Gt,
758             hir_def::hir::CmpOp::Ord { ordering: Ordering::Less, strict: false } => BinOp::Le,
759             hir_def::hir::CmpOp::Ord { ordering: Ordering::Less, strict: true } => BinOp::Lt,
760         }
761     }
762 }
763 
764 impl From<Operand> for Rvalue {
from(x: Operand) -> Self765     fn from(x: Operand) -> Self {
766         Self::Use(x)
767     }
768 }
769 
770 #[derive(Debug, PartialEq, Eq, Clone)]
771 pub enum CastKind {
772     /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
773     /// between a function pointer and an integer type.
774     /// See the docs on `expose_addr` for more details.
775     PointerExposeAddress,
776     /// An address-to-pointer cast that picks up an exposed provenance.
777     /// See the docs on `from_exposed_addr` for more details.
778     PointerFromExposedAddress,
779     /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are
780     /// translated into `&raw mut/const *r`, i.e., they are not actually casts.
781     Pointer(PointerCast),
782     /// Cast into a dyn* object.
783     DynStar,
784     IntToInt,
785     FloatToInt,
786     FloatToFloat,
787     IntToFloat,
788     FnPtrToPtr,
789 }
790 
791 #[derive(Debug, PartialEq, Eq, Clone)]
792 pub enum Rvalue {
793     /// Yields the operand unchanged
794     Use(Operand),
795 
796     /// Creates an array where each element is the value of the operand.
797     ///
798     /// Corresponds to source code like `[x; 32]`.
799     Repeat(Operand, Const),
800 
801     /// Creates a reference of the indicated kind to the place.
802     ///
803     /// There is not much to document here, because besides the obvious parts the semantics of this
804     /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing
805     /// exactly what the behavior of this operation should be.
806     ///
807     /// `Shallow` borrows are disallowed after drop lowering.
808     Ref(BorrowKind, Place),
809 
810     /// Creates a pointer/reference to the given thread local.
811     ///
812     /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
813     /// `*const T`, and if neither of those apply a `&T`.
814     ///
815     /// **Note:** This is a runtime operation that actually executes code and is in this sense more
816     /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
817     /// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
818     ///
819     /// **Needs clarification**: Are there weird additional semantics here related to the runtime
820     /// nature of this operation?
821     //ThreadLocalRef(DefId),
822 
823     /// Creates a pointer with the indicated mutability to the place.
824     ///
825     /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
826     /// `&raw v` or `addr_of!(v)`.
827     ///
828     /// Like with references, the semantics of this operation are heavily dependent on the aliasing
829     /// model.
830     //AddressOf(Mutability, Place),
831 
832     /// Yields the length of the place, as a `usize`.
833     ///
834     /// If the type of the place is an array, this is the array length. For slices (`[T]`, not
835     /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
836     /// ill-formed for places of other types.
837     Len(Place),
838 
839     /// Performs essentially all of the casts that can be performed via `as`.
840     ///
841     /// This allows for casts from/to a variety of types.
842     ///
843     /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why
844     /// `ArrayToPointer` and `MutToConstPointer` are special.
845     Cast(CastKind, Operand, Ty),
846 
847     // FIXME link to `pointer::offset` when it hits stable.
848     /// * `Offset` has the same semantics as `pointer::offset`, except that the second
849     ///   parameter may be a `usize` as well.
850     /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
851     ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
852     ///   matching, up to the usual caveat of the lifetimes in function pointers.
853     /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
854     ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
855     ///   truncated as needed.
856     /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
857     ///   types and return a value of that type.
858     /// * The remaining operations accept signed integers, unsigned integers, or floats with
859     ///   matching types and return a value of that type.
860     //BinaryOp(BinOp, Box<(Operand, Operand)>),
861 
862     /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
863     ///
864     /// When overflow checking is disabled and we are generating run-time code, the error condition
865     /// is false. Otherwise, and always during CTFE, the error condition is determined as described
866     /// below.
867     ///
868     /// For addition, subtraction, and multiplication on integers the error condition is set when
869     /// the infinite precision result would be unequal to the actual result.
870     ///
871     /// For shift operations on integers the error condition is set when the value of right-hand
872     /// side is greater than or equal to the number of bits in the type of the left-hand side, or
873     /// when the value of right-hand side is negative.
874     ///
875     /// Other combinations of types and operators are unsupported.
876     CheckedBinaryOp(BinOp, Operand, Operand),
877 
878     /// Computes a value as described by the operation.
879     //NullaryOp(NullOp, Ty),
880 
881     /// Exactly like `BinaryOp`, but less operands.
882     ///
883     /// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
884     /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
885     /// return a value with the same type as their operand.
886     UnaryOp(UnOp, Operand),
887 
888     /// Computes the discriminant of the place, returning it as an integer of type
889     /// [`discriminant_ty`]. Returns zero for types without discriminant.
890     ///
891     /// The validity requirements for the underlying value are undecided for this rvalue, see
892     /// [#91095]. Note too that the value of the discriminant is not the same thing as the
893     /// variant index; use [`discriminant_for_variant`] to convert.
894     ///
895     /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
896     /// [#91095]: https://github.com/rust-lang/rust/issues/91095
897     /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
898     Discriminant(Place),
899 
900     /// Creates an aggregate value, like a tuple or struct.
901     ///
902     /// This is needed because dataflow analysis needs to distinguish
903     /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
904     /// has a destructor.
905     ///
906     /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After
907     /// generator lowering, `Generator` aggregate kinds are disallowed too.
908     Aggregate(AggregateKind, Box<[Operand]>),
909 
910     /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
911     ///
912     /// This is different from a normal transmute because dataflow analysis will treat the box as
913     /// initialized but its content as uninitialized. Like other pointer casts, this in general
914     /// affects alias analysis.
915     ShallowInitBox(Operand, Ty),
916 
917     /// NON STANDARD: allocates memory with the type's layout, and shallow init the box with the resulting pointer.
918     ShallowInitBoxWithAlloc(Ty),
919 
920     /// A CopyForDeref is equivalent to a read from a place at the
921     /// codegen level, but is treated specially by drop elaboration. When such a read happens, it
922     /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator)
923     /// that the only use of the returned value is a deref operation, immediately
924     /// followed by one or more projections. Drop elaboration treats this rvalue as if the
925     /// read never happened and just projects further. This allows simplifying various MIR
926     /// optimizations and codegen backends that previously had to handle deref operations anywhere
927     /// in a place.
928     CopyForDeref(Place),
929 }
930 
931 #[derive(Debug, PartialEq, Eq, Clone)]
932 pub enum StatementKind {
933     Assign(Place, Rvalue),
934     //FakeRead(Box<(FakeReadCause, Place)>),
935     //SetDiscriminant {
936     //    place: Box<Place>,
937     //    variant_index: VariantIdx,
938     //},
939     Deinit(Place),
940     StorageLive(LocalId),
941     StorageDead(LocalId),
942     //Retag(RetagKind, Box<Place>),
943     //AscribeUserType(Place, UserTypeProjection, Variance),
944     //Intrinsic(Box<NonDivergingIntrinsic>),
945     Nop,
946 }
947 impl StatementKind {
with_span(self, span: MirSpan) -> Statement948     fn with_span(self, span: MirSpan) -> Statement {
949         Statement { kind: self, span }
950     }
951 }
952 
953 #[derive(Debug, PartialEq, Eq, Clone)]
954 pub struct Statement {
955     pub kind: StatementKind,
956     pub span: MirSpan,
957 }
958 
959 #[derive(Debug, Default, Clone, PartialEq, Eq)]
960 pub struct BasicBlock {
961     /// List of statements in this block.
962     pub statements: Vec<Statement>,
963 
964     /// Terminator for this block.
965     ///
966     /// N.B., this should generally ONLY be `None` during construction.
967     /// Therefore, you should generally access it via the
968     /// `terminator()` or `terminator_mut()` methods. The only
969     /// exception is that certain passes, such as `simplify_cfg`, swap
970     /// out the terminator temporarily with `None` while they continue
971     /// to recurse over the set of basic blocks.
972     pub terminator: Option<Terminator>,
973 
974     /// If true, this block lies on an unwind path. This is used
975     /// during codegen where distinct kinds of basic blocks may be
976     /// generated (particularly for MSVC cleanup). Unwind blocks must
977     /// only branch to other unwind blocks.
978     pub is_cleanup: bool,
979 }
980 
981 #[derive(Debug, Clone, PartialEq, Eq)]
982 pub struct MirBody {
983     pub basic_blocks: Arena<BasicBlock>,
984     pub locals: Arena<Local>,
985     pub start_block: BasicBlockId,
986     pub owner: DefWithBodyId,
987     pub binding_locals: ArenaMap<BindingId, LocalId>,
988     pub param_locals: Vec<LocalId>,
989     /// This field stores the closures directly owned by this body. It is used
990     /// in traversing every mir body.
991     pub closures: Vec<ClosureId>,
992 }
993 
994 impl MirBody {
walk_places(&mut self, mut f: impl FnMut(&mut Place))995     fn walk_places(&mut self, mut f: impl FnMut(&mut Place)) {
996         fn for_operand(op: &mut Operand, f: &mut impl FnMut(&mut Place)) {
997             match op {
998                 Operand::Copy(p) | Operand::Move(p) => {
999                     f(p);
1000                 }
1001                 Operand::Constant(_) | Operand::Static(_) => (),
1002             }
1003         }
1004         for (_, block) in self.basic_blocks.iter_mut() {
1005             for statement in &mut block.statements {
1006                 match &mut statement.kind {
1007                     StatementKind::Assign(p, r) => {
1008                         f(p);
1009                         match r {
1010                             Rvalue::ShallowInitBoxWithAlloc(_) => (),
1011                             Rvalue::ShallowInitBox(o, _)
1012                             | Rvalue::UnaryOp(_, o)
1013                             | Rvalue::Cast(_, o, _)
1014                             | Rvalue::Repeat(o, _)
1015                             | Rvalue::Use(o) => for_operand(o, &mut f),
1016                             Rvalue::CopyForDeref(p)
1017                             | Rvalue::Discriminant(p)
1018                             | Rvalue::Len(p)
1019                             | Rvalue::Ref(_, p) => f(p),
1020                             Rvalue::CheckedBinaryOp(_, o1, o2) => {
1021                                 for_operand(o1, &mut f);
1022                                 for_operand(o2, &mut f);
1023                             }
1024                             Rvalue::Aggregate(_, ops) => {
1025                                 for op in ops.iter_mut() {
1026                                     for_operand(op, &mut f);
1027                                 }
1028                             }
1029                         }
1030                     }
1031                     StatementKind::Deinit(p) => f(p),
1032                     StatementKind::StorageLive(_)
1033                     | StatementKind::StorageDead(_)
1034                     | StatementKind::Nop => (),
1035                 }
1036             }
1037             match &mut block.terminator {
1038                 Some(x) => match &mut x.kind {
1039                     TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, &mut f),
1040                     TerminatorKind::FalseEdge { .. }
1041                     | TerminatorKind::FalseUnwind { .. }
1042                     | TerminatorKind::Goto { .. }
1043                     | TerminatorKind::Resume
1044                     | TerminatorKind::GeneratorDrop
1045                     | TerminatorKind::Abort
1046                     | TerminatorKind::Return
1047                     | TerminatorKind::Unreachable => (),
1048                     TerminatorKind::Drop { place, .. } => {
1049                         f(place);
1050                     }
1051                     TerminatorKind::DropAndReplace { place, value, .. } => {
1052                         f(place);
1053                         for_operand(value, &mut f);
1054                     }
1055                     TerminatorKind::Call { func, args, destination, .. } => {
1056                         for_operand(func, &mut f);
1057                         args.iter_mut().for_each(|x| for_operand(x, &mut f));
1058                         f(destination);
1059                     }
1060                     TerminatorKind::Assert { cond, .. } => {
1061                         for_operand(cond, &mut f);
1062                     }
1063                     TerminatorKind::Yield { value, resume_arg, .. } => {
1064                         for_operand(value, &mut f);
1065                         f(resume_arg);
1066                     }
1067                 },
1068                 None => (),
1069             }
1070         }
1071     }
1072 
shrink_to_fit(&mut self)1073     fn shrink_to_fit(&mut self) {
1074         let MirBody {
1075             basic_blocks,
1076             locals,
1077             start_block: _,
1078             owner: _,
1079             binding_locals,
1080             param_locals,
1081             closures,
1082         } = self;
1083         basic_blocks.shrink_to_fit();
1084         locals.shrink_to_fit();
1085         binding_locals.shrink_to_fit();
1086         param_locals.shrink_to_fit();
1087         closures.shrink_to_fit();
1088         for (_, b) in basic_blocks.iter_mut() {
1089             let BasicBlock { statements, terminator: _, is_cleanup: _ } = b;
1090             statements.shrink_to_fit();
1091         }
1092     }
1093 }
1094 
1095 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
1096 pub enum MirSpan {
1097     ExprId(ExprId),
1098     PatId(PatId),
1099     Unknown,
1100 }
1101 
1102 impl_from!(ExprId, PatId for MirSpan);
1103