]>
Commit | Line | Data |
---|---|---|
064997fb FG |
1 | //! This defines the syntax of MIR, i.e., the set of available MIR operations, and other definitions |
2 | //! closely related to MIR semantics. | |
3 | //! This is in a dedicated file so that changes to this file can be reviewed more carefully. | |
4 | //! The intention is that this file only contains datatype declarations, no code. | |
5 | ||
6 | use super::{BasicBlock, Constant, Field, Local, SwitchTargets, UserTypeProjection}; | |
7 | ||
8 | use crate::mir::coverage::{CodeRegion, CoverageKind}; | |
487cf647 | 9 | use crate::traits::Reveal; |
064997fb FG |
10 | use crate::ty::adjustment::PointerCast; |
11 | use crate::ty::subst::SubstsRef; | |
12 | use crate::ty::{self, List, Ty}; | |
13 | use crate::ty::{Region, UserTypeAnnotationIndex}; | |
14 | ||
15 | use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; | |
16 | use rustc_hir::def_id::DefId; | |
17 | use rustc_hir::{self as hir}; | |
18 | use rustc_hir::{self, GeneratorKind}; | |
19 | use rustc_target::abi::VariantIdx; | |
20 | ||
21 | use rustc_ast::Mutability; | |
22 | use rustc_span::def_id::LocalDefId; | |
23 | use rustc_span::symbol::Symbol; | |
24 | use rustc_span::Span; | |
25 | use rustc_target::asm::InlineAsmRegOrRegClass; | |
26 | ||
f2b60f7d | 27 | /// Represents the "flavors" of MIR. |
064997fb | 28 | /// |
f2b60f7d FG |
29 | /// All flavors of MIR use the same data structure, but there are some important differences. These |
30 | /// differences come in two forms: Dialects and phases. | |
064997fb | 31 | /// |
f2b60f7d FG |
32 | /// Dialects represent a stronger distinction than phases. This is because the transitions between |
33 | /// dialects are semantic changes, and therefore technically *lowerings* between distinct IRs. In | |
34 | /// other words, the same [`Body`](crate::mir::Body) might be well-formed for multiple dialects, but | |
35 | /// have different semantic meaning and different behavior at runtime. | |
36 | /// | |
37 | /// Each dialect additionally has a number of phases. However, phase changes never involve semantic | |
38 | /// changes. If some MIR is well-formed both before and after a phase change, it is also guaranteed | |
39 | /// that it has the same semantic meaning. In this sense, phase changes can only add additional | |
40 | /// restrictions on what MIR is well-formed. | |
41 | /// | |
42 | /// When adding phases, remember to update [`MirPhase::phase_index`]. | |
064997fb FG |
43 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] |
44 | #[derive(HashStable)] | |
45 | pub enum MirPhase { | |
f2b60f7d FG |
46 | /// The MIR that is generated by MIR building. |
47 | /// | |
48 | /// The only things that operate on this dialect are unsafeck, the various MIR lints, and const | |
49 | /// qualifs. | |
50 | /// | |
51 | /// This has no distinct phases. | |
52 | Built, | |
53 | /// The MIR used for most analysis. | |
54 | /// | |
55 | /// The only semantic change between analysis and built MIR is constant promotion. In built MIR, | |
56 | /// sequences of statements that would generally be subject to constant promotion are | |
57 | /// semantically constants, while in analysis MIR all constants are explicit. | |
58 | /// | |
59 | /// The result of const promotion is available from the `mir_promoted` and `promoted_mir` queries. | |
60 | /// | |
61 | /// This is the version of MIR used by borrowck and friends. | |
62 | Analysis(AnalysisPhase), | |
63 | /// The MIR used for CTFE, optimizations, and codegen. | |
64 | /// | |
65 | /// The semantic changes that occur in the lowering from analysis to runtime MIR are as follows: | |
66 | /// | |
67 | /// - Drops: In analysis MIR, `Drop` terminators represent *conditional* drops; roughly speaking, | |
68 | /// if dataflow analysis determines that the place being dropped is uninitialized, the drop will | |
69 | /// not be executed. The exact semantics of this aren't written down anywhere, which means they | |
70 | /// are essentially "what drop elaboration does." In runtime MIR, the drops are unconditional; | |
71 | /// when a `Drop` terminator is reached, if the type has drop glue that drop glue is always | |
72 | /// executed. This may be UB if the underlying place is not initialized. | |
73 | /// - Packed drops: Places might in general be misaligned - in most cases this is UB, the exception | |
74 | /// is fields of packed structs. In analysis MIR, `Drop(P)` for a `P` that might be misaligned | |
75 | /// for this reason implicitly moves `P` to a temporary before dropping. Runtime MIR has no such | |
76 | /// rules, and dropping a misaligned place is simply UB. | |
77 | /// - Unwinding: in analysis MIR, unwinding from a function which may not unwind aborts. In runtime | |
78 | /// MIR, this is UB. | |
79 | /// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way | |
80 | /// that Rust itself has them. Where exactly these are is generally subject to change, and so we | |
81 | /// don't document this here. Runtime MIR has all retags explicit. | |
82 | /// - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has | |
83 | /// access to. This occurs in generator bodies. Such locals do not behave like other locals, | |
84 | /// because they eg may be aliased in surprising ways. Runtime MIR has no such special locals - | |
85 | /// all generator bodies are lowered and so all places that look like locals really are locals. | |
2b03887a FG |
86 | /// |
87 | /// Also note that the lint pass which reports eg `200_u8 + 200_u8` as an error is run as a part | |
88 | /// of analysis to runtime MIR lowering. To ensure lints are reported reliably, this means that | |
487cf647 | 89 | /// transformations which may suppress such errors should not run on analysis MIR. |
f2b60f7d FG |
90 | Runtime(RuntimePhase), |
91 | } | |
92 | ||
487cf647 FG |
93 | impl MirPhase { |
94 | pub fn name(&self) -> &'static str { | |
95 | match *self { | |
96 | MirPhase::Built => "built", | |
97 | MirPhase::Analysis(AnalysisPhase::Initial) => "analysis", | |
98 | MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup", | |
99 | MirPhase::Runtime(RuntimePhase::Initial) => "runtime", | |
100 | MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup", | |
101 | MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized", | |
102 | } | |
103 | } | |
104 | ||
105 | pub fn reveal(&self) -> Reveal { | |
106 | match *self { | |
107 | MirPhase::Built | MirPhase::Analysis(_) => Reveal::UserFacing, | |
108 | MirPhase::Runtime(_) => Reveal::All, | |
109 | } | |
110 | } | |
111 | } | |
112 | ||
f2b60f7d FG |
113 | /// See [`MirPhase::Analysis`]. |
114 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] | |
115 | #[derive(HashStable)] | |
116 | pub enum AnalysisPhase { | |
117 | Initial = 0, | |
118 | /// Beginning in this phase, the following variants are disallowed: | |
064997fb FG |
119 | /// * [`TerminatorKind::FalseUnwind`] |
120 | /// * [`TerminatorKind::FalseEdge`] | |
121 | /// * [`StatementKind::FakeRead`] | |
122 | /// * [`StatementKind::AscribeUserType`] | |
123 | /// * [`Rvalue::Ref`] with `BorrowKind::Shallow` | |
124 | /// | |
f2b60f7d FG |
125 | /// Furthermore, `Deref` projections must be the first projection within any place (if they |
126 | /// appear at all) | |
127 | PostCleanup = 1, | |
128 | } | |
129 | ||
130 | /// See [`MirPhase::Runtime`]. | |
131 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] | |
132 | #[derive(HashStable)] | |
133 | pub enum RuntimePhase { | |
134 | /// In addition to the semantic changes, beginning with this phase, the following variants are | |
135 | /// disallowed: | |
136 | /// * [`TerminatorKind::DropAndReplace`] | |
137 | /// * [`TerminatorKind::Yield`] | |
138 | /// * [`TerminatorKind::GeneratorDrop`] | |
064997fb FG |
139 | /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array` |
140 | /// | |
f2b60f7d FG |
141 | /// And the following variants are allowed: |
142 | /// * [`StatementKind::Retag`] | |
064997fb | 143 | /// * [`StatementKind::SetDiscriminant`] |
f2b60f7d FG |
144 | /// * [`StatementKind::Deinit`] |
145 | /// | |
146 | /// Furthermore, `Copy` operands are allowed for non-`Copy` types. | |
147 | Initial = 0, | |
148 | /// Beginning with this phase, the following variant is disallowed: | |
064997fb | 149 | /// * [`ProjectionElem::Deref`] of `Box` |
f2b60f7d FG |
150 | PostCleanup = 1, |
151 | Optimized = 2, | |
064997fb FG |
152 | } |
153 | ||
154 | /////////////////////////////////////////////////////////////////////////// | |
155 | // Borrow kinds | |
156 | ||
157 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] | |
158 | #[derive(Hash, HashStable)] | |
159 | pub enum BorrowKind { | |
160 | /// Data must be immutable and is aliasable. | |
161 | Shared, | |
162 | ||
163 | /// The immediately borrowed place must be immutable, but projections from | |
164 | /// it don't need to be. For example, a shallow borrow of `a.b` doesn't | |
165 | /// conflict with a mutable borrow of `a.b.c`. | |
166 | /// | |
167 | /// This is used when lowering matches: when matching on a place we want to | |
168 | /// ensure that place have the same value from the start of the match until | |
169 | /// an arm is selected. This prevents this code from compiling: | |
170 | /// ```compile_fail,E0510 | |
171 | /// let mut x = &Some(0); | |
172 | /// match *x { | |
173 | /// None => (), | |
174 | /// Some(_) if { x = &None; false } => (), | |
175 | /// Some(_) => (), | |
176 | /// } | |
177 | /// ``` | |
178 | /// This can't be a shared borrow because mutably borrowing (*x as Some).0 | |
179 | /// should not prevent `if let None = x { ... }`, for example, because the | |
180 | /// mutating `(*x as Some).0` can't affect the discriminant of `x`. | |
181 | /// We can also report errors with this kind of borrow differently. | |
182 | Shallow, | |
183 | ||
184 | /// Data must be immutable but not aliasable. This kind of borrow | |
185 | /// cannot currently be expressed by the user and is used only in | |
186 | /// implicit closure bindings. It is needed when the closure is | |
187 | /// borrowing or mutating a mutable referent, e.g.: | |
188 | /// ``` | |
189 | /// let mut z = 3; | |
190 | /// let x: &mut isize = &mut z; | |
191 | /// let y = || *x += 5; | |
192 | /// ``` | |
193 | /// If we were to try to translate this closure into a more explicit | |
194 | /// form, we'd encounter an error with the code as written: | |
195 | /// ```compile_fail,E0594 | |
196 | /// struct Env<'a> { x: &'a &'a mut isize } | |
197 | /// let mut z = 3; | |
198 | /// let x: &mut isize = &mut z; | |
199 | /// let y = (&mut Env { x: &x }, fn_ptr); // Closure is pair of env and fn | |
200 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
201 | /// ``` | |
202 | /// This is then illegal because you cannot mutate an `&mut` found | |
203 | /// in an aliasable location. To solve, you'd have to translate with | |
204 | /// an `&mut` borrow: | |
205 | /// ```compile_fail,E0596 | |
206 | /// struct Env<'a> { x: &'a mut &'a mut isize } | |
207 | /// let mut z = 3; | |
208 | /// let x: &mut isize = &mut z; | |
209 | /// let y = (&mut Env { x: &mut x }, fn_ptr); // changed from &x to &mut x | |
210 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
211 | /// ``` | |
212 | /// Now the assignment to `**env.x` is legal, but creating a | |
213 | /// mutable pointer to `x` is not because `x` is not mutable. We | |
214 | /// could fix this by declaring `x` as `let mut x`. This is ok in | |
215 | /// user code, if awkward, but extra weird for closures, since the | |
216 | /// borrow is hidden. | |
217 | /// | |
218 | /// So we introduce a "unique imm" borrow -- the referent is | |
219 | /// immutable, but not aliasable. This solves the problem. For | |
220 | /// simplicity, we don't give users the way to express this | |
221 | /// borrow, it's just used when translating closures. | |
222 | Unique, | |
223 | ||
224 | /// Data is mutable and not aliasable. | |
225 | Mut { | |
226 | /// `true` if this borrow arose from method-call auto-ref | |
227 | /// (i.e., `adjustment::Adjust::Borrow`). | |
228 | allow_two_phase_borrow: bool, | |
229 | }, | |
230 | } | |
231 | ||
232 | /////////////////////////////////////////////////////////////////////////// | |
233 | // Statements | |
234 | ||
235 | /// The various kinds of statements that can appear in MIR. | |
236 | /// | |
237 | /// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which | |
238 | /// ones you do not have to worry about. The MIR validator will generally enforce such restrictions, | |
239 | /// causing an ICE if they are violated. | |
240 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] | |
241 | #[derive(TypeFoldable, TypeVisitable)] | |
242 | pub enum StatementKind<'tcx> { | |
243 | /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except | |
244 | /// without the possibility of dropping the previous value (that must be done separately, if at | |
245 | /// all). The *exact* way this works is undecided. It probably does something like evaluating | |
246 | /// the LHS to a place and the RHS to a value, and then storing the value to the place. Various | |
247 | /// parts of this may do type specific things that are more complicated than simply copying | |
248 | /// bytes. | |
249 | /// | |
250 | /// **Needs clarification**: The implication of the above idea would be that assignment implies | |
251 | /// that the resulting value is initialized. I believe we could commit to this separately from | |
252 | /// committing to whatever part of the memory model we would need to decide on to make the above | |
253 | /// paragragh precise. Do we want to? | |
254 | /// | |
255 | /// Assignments in which the types of the place and rvalue differ are not well-formed. | |
256 | /// | |
257 | /// **Needs clarification**: Do we ever want to worry about non-free (in the body) lifetimes for | |
258 | /// the typing requirement in post drop-elaboration MIR? I think probably not - I'm not sure we | |
259 | /// could meaningfully require this anyway. How about free lifetimes? Is ignoring this | |
260 | /// interesting for optimizations? Do we want to allow such optimizations? | |
261 | /// | |
262 | /// **Needs clarification**: We currently require that the LHS place not overlap with any place | |
263 | /// read as part of computation of the RHS for some rvalues (generally those not producing | |
264 | /// primitives). This requirement is under discussion in [#68364]. As a part of this discussion, | |
265 | /// it is also unclear in what order the components are evaluated. | |
266 | /// | |
267 | /// [#68364]: https://github.com/rust-lang/rust/issues/68364 | |
268 | /// | |
269 | /// See [`Rvalue`] documentation for details on each of those. | |
270 | Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), | |
271 | ||
272 | /// This represents all the reading that a pattern match may do (e.g., inspecting constants and | |
273 | /// discriminant values), and the kind of pattern it comes from. This is in order to adapt | |
274 | /// potential error messages to these specific patterns. | |
275 | /// | |
276 | /// Note that this also is emitted for regular `let` bindings to ensure that locals that are | |
277 | /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` | |
278 | /// | |
279 | /// When executed at runtime this is a nop. | |
280 | /// | |
281 | /// Disallowed after drop elaboration. | |
282 | FakeRead(Box<(FakeReadCause, Place<'tcx>)>), | |
283 | ||
284 | /// Write the discriminant for a variant to the enum Place. | |
285 | /// | |
286 | /// This is permitted for both generators and ADTs. This does not necessarily write to the | |
287 | /// entire place; instead, it writes to the minimum set of bytes as required by the layout for | |
288 | /// the type. | |
289 | SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx }, | |
290 | ||
291 | /// Deinitializes the place. | |
292 | /// | |
293 | /// This writes `uninit` bytes to the entire place. | |
294 | Deinit(Box<Place<'tcx>>), | |
295 | ||
296 | /// `StorageLive` and `StorageDead` statements mark the live range of a local. | |
297 | /// | |
298 | /// At any point during the execution of a function, each local is either allocated or | |
299 | /// unallocated. Except as noted below, all locals except function parameters are initially | |
300 | /// unallocated. `StorageLive` statements cause memory to be allocated for the local while | |
301 | /// `StorageDead` statements cause the memory to be freed. Using a local in any way (not only | |
302 | /// reading/writing from it) while it is unallocated is UB. | |
303 | /// | |
304 | /// Some locals have no `StorageLive` or `StorageDead` statements within the entire MIR body. | |
305 | /// These locals are implicitly allocated for the full duration of the function. There is a | |
306 | /// convenience method at `rustc_mir_dataflow::storage::always_storage_live_locals` for | |
307 | /// computing these locals. | |
308 | /// | |
309 | /// If the local is already allocated, calling `StorageLive` again is UB. However, for an | |
310 | /// unallocated local an additional `StorageDead` all is simply a nop. | |
311 | StorageLive(Local), | |
312 | ||
313 | /// See `StorageLive` above. | |
314 | StorageDead(Local), | |
315 | ||
316 | /// Retag references in the given place, ensuring they got fresh tags. | |
317 | /// | |
318 | /// This is part of the Stacked Borrows model. These statements are currently only interpreted | |
319 | /// by miri and only generated when `-Z mir-emit-retag` is passed. See | |
320 | /// <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> for | |
321 | /// more details. | |
322 | /// | |
323 | /// For code that is not specific to stacked borrows, you should consider retags to read | |
324 | /// and modify the place in an opaque way. | |
325 | Retag(RetagKind, Box<Place<'tcx>>), | |
326 | ||
327 | /// Encodes a user's type ascription. These need to be preserved | |
328 | /// intact so that NLL can respect them. For example: | |
329 | /// ```ignore (illustrative) | |
330 | /// let a: T = y; | |
331 | /// ``` | |
332 | /// The effect of this annotation is to relate the type `T_y` of the place `y` | |
333 | /// to the user-given type `T`. The effect depends on the specified variance: | |
334 | /// | |
335 | /// - `Covariant` -- requires that `T_y <: T` | |
336 | /// - `Contravariant` -- requires that `T_y :> T` | |
337 | /// - `Invariant` -- requires that `T_y == T` | |
338 | /// - `Bivariant` -- no effect | |
339 | /// | |
340 | /// When executed at runtime this is a nop. | |
341 | /// | |
342 | /// Disallowed after drop elaboration. | |
343 | AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), | |
344 | ||
345 | /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A | |
346 | /// `Coverage` statement carries metadata about the coverage region, used to inject a coverage | |
347 | /// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates | |
348 | /// executable code, to increment a counter variable at runtime, each time the code region is | |
349 | /// executed. | |
350 | Coverage(Box<Coverage>), | |
351 | ||
f2b60f7d FG |
352 | /// Denotes a call to an intrinsic that does not require an unwind path and always returns. |
353 | /// This avoids adding a new block and a terminator for simple intrinsics. | |
354 | Intrinsic(Box<NonDivergingIntrinsic<'tcx>>), | |
355 | ||
356 | /// No-op. Useful for deleting instructions without affecting statement indices. | |
357 | Nop, | |
358 | } | |
359 | ||
360 | #[derive( | |
361 | Clone, | |
362 | TyEncodable, | |
363 | TyDecodable, | |
364 | Debug, | |
365 | PartialEq, | |
366 | Hash, | |
367 | HashStable, | |
368 | TypeFoldable, | |
369 | TypeVisitable | |
370 | )] | |
371 | pub enum NonDivergingIntrinsic<'tcx> { | |
372 | /// Denotes a call to the intrinsic function `assume`. | |
373 | /// | |
374 | /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its | |
375 | /// computation to infer information about other variables. So if the boolean came from a | |
376 | /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks. | |
377 | /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`. | |
378 | Assume(Operand<'tcx>), | |
379 | ||
064997fb FG |
380 | /// Denotes a call to the intrinsic function `copy_nonoverlapping`. |
381 | /// | |
382 | /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer, | |
383 | /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and | |
384 | /// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of | |
f2b60f7d | 385 | /// the `src` place are copied to the contiguous range of bytes beginning with the first byte |
064997fb FG |
386 | /// of `dest`. |
387 | /// | |
388 | /// **Needs clarification**: In what order are operands computed and dereferenced? It should | |
389 | /// probably match the order for assignment, but that is also undecided. | |
390 | /// | |
391 | /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved? | |
392 | /// I vaguely remember Ralf saying somewhere that he thought it should not be. | |
f2b60f7d FG |
393 | CopyNonOverlapping(CopyNonOverlapping<'tcx>), |
394 | } | |
064997fb | 395 | |
f2b60f7d FG |
396 | impl std::fmt::Display for NonDivergingIntrinsic<'_> { |
397 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
398 | match self { | |
399 | Self::Assume(op) => write!(f, "assume({op:?})"), | |
400 | Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { | |
401 | write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})") | |
402 | } | |
403 | } | |
404 | } | |
064997fb FG |
405 | } |
406 | ||
407 | /// Describes what kind of retag is to be performed. | |
408 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)] | |
409 | #[rustc_pass_by_value] | |
410 | pub enum RetagKind { | |
487cf647 | 411 | /// The initial retag of arguments when entering a function. |
064997fb FG |
412 | FnEntry, |
413 | /// Retag preparing for a two-phase borrow. | |
414 | TwoPhase, | |
415 | /// Retagging raw pointers. | |
416 | Raw, | |
417 | /// A "normal" retag. | |
418 | Default, | |
419 | } | |
420 | ||
421 | /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. | |
422 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)] | |
423 | pub enum FakeReadCause { | |
424 | /// Inject a fake read of the borrowed input at the end of each guards | |
425 | /// code. | |
426 | /// | |
427 | /// This should ensure that you cannot change the variant for an enum while | |
428 | /// you are in the midst of matching on it. | |
429 | ForMatchGuard, | |
430 | ||
431 | /// `let x: !; match x {}` doesn't generate any read of x so we need to | |
432 | /// generate a read of x to check that it is initialized and safe. | |
433 | /// | |
434 | /// If a closure pattern matches a Place starting with an Upvar, then we introduce a | |
435 | /// FakeRead for that Place outside the closure, in such a case this option would be | |
436 | /// Some(closure_def_id). | |
437 | /// Otherwise, the value of the optional LocalDefId will be None. | |
438 | // | |
f2b60f7d | 439 | // We can use LocalDefId here since fake read statements are removed |
064997fb FG |
440 | // before codegen in the `CleanupNonCodegenStatements` pass. |
441 | ForMatchedPlace(Option<LocalDefId>), | |
442 | ||
443 | /// A fake read of the RefWithinGuard version of a bind-by-value variable | |
444 | /// in a match guard to ensure that its value hasn't change by the time | |
445 | /// we create the OutsideGuard version. | |
446 | ForGuardBinding, | |
447 | ||
448 | /// Officially, the semantics of | |
449 | /// | |
450 | /// `let pattern = <expr>;` | |
451 | /// | |
452 | /// is that `<expr>` is evaluated into a temporary and then this temporary is | |
453 | /// into the pattern. | |
454 | /// | |
455 | /// However, if we see the simple pattern `let var = <expr>`, we optimize this to | |
456 | /// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable, | |
457 | /// but in some cases it can affect the borrow checker, as in #53695. | |
458 | /// Therefore, we insert a "fake read" here to ensure that we get | |
459 | /// appropriate errors. | |
460 | /// | |
461 | /// If a closure pattern matches a Place starting with an Upvar, then we introduce a | |
462 | /// FakeRead for that Place outside the closure, in such a case this option would be | |
463 | /// Some(closure_def_id). | |
464 | /// Otherwise, the value of the optional DefId will be None. | |
465 | ForLet(Option<LocalDefId>), | |
466 | ||
467 | /// If we have an index expression like | |
468 | /// | |
469 | /// (*x)[1][{ x = y; 4}] | |
470 | /// | |
471 | /// then the first bounds check is invalidated when we evaluate the second | |
472 | /// index expression. Thus we create a fake borrow of `x` across the second | |
473 | /// indexer, which will cause a borrow check error. | |
474 | ForIndex, | |
475 | } | |
476 | ||
477 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] | |
478 | #[derive(TypeFoldable, TypeVisitable)] | |
479 | pub struct Coverage { | |
480 | pub kind: CoverageKind, | |
481 | pub code_region: Option<CodeRegion>, | |
482 | } | |
483 | ||
484 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] | |
485 | #[derive(TypeFoldable, TypeVisitable)] | |
486 | pub struct CopyNonOverlapping<'tcx> { | |
487 | pub src: Operand<'tcx>, | |
488 | pub dst: Operand<'tcx>, | |
489 | /// Number of elements to copy from src to dest, not bytes. | |
490 | pub count: Operand<'tcx>, | |
491 | } | |
492 | ||
493 | /////////////////////////////////////////////////////////////////////////// | |
494 | // Terminators | |
495 | ||
496 | /// The various kinds of terminators, representing ways of exiting from a basic block. | |
497 | /// | |
498 | /// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the | |
499 | /// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such | |
500 | /// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then | |
501 | /// once the current function is reached, execution continues at the given basic block, if any. If | |
502 | /// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is | |
503 | /// equivalent to the execution of a `Resume` terminator. | |
504 | /// | |
505 | /// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup` | |
506 | /// basic blocks have a couple restrictions: | |
507 | /// 1. All `cleanup` fields in them must be `None`. | |
508 | /// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are. | |
509 | /// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks | |
510 | /// must also be `cleanup`. This is a part of the type system and checked statically, so it is | |
511 | /// still an error to have such an edge in the CFG even if it's known that it won't be taken at | |
512 | /// runtime. | |
f2b60f7d | 513 | #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] |
064997fb FG |
514 | pub enum TerminatorKind<'tcx> { |
515 | /// Block has one successor; we continue execution there. | |
516 | Goto { target: BasicBlock }, | |
517 | ||
518 | /// Switches based on the computed value. | |
519 | /// | |
520 | /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned | |
521 | /// integer, char, or bool, and must match the given type. Then, if the list of switch targets | |
522 | /// contains the computed value, continues execution at the associated basic block. Otherwise, | |
523 | /// continues execution at the "otherwise" basic block. | |
524 | /// | |
525 | /// Target values may not appear more than once. | |
526 | SwitchInt { | |
527 | /// The discriminant value being tested. | |
528 | discr: Operand<'tcx>, | |
529 | ||
530 | /// The type of value being tested. | |
531 | /// This is always the same as the type of `discr`. | |
532 | /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing. | |
533 | switch_ty: Ty<'tcx>, | |
534 | ||
535 | targets: SwitchTargets, | |
536 | }, | |
537 | ||
538 | /// Indicates that the landing pad is finished and that the process should continue unwinding. | |
539 | /// | |
540 | /// Like a return, this marks the end of this invocation of the function. | |
541 | /// | |
542 | /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after | |
543 | /// deaggregation runs. | |
544 | Resume, | |
545 | ||
546 | /// Indicates that the landing pad is finished and that the process should abort. | |
547 | /// | |
548 | /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in | |
549 | /// cleanup blocks. | |
550 | Abort, | |
551 | ||
552 | /// Returns from the function. | |
553 | /// | |
554 | /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very | |
555 | /// likely at least assigns the value currently in the return place (`_0`) to the place | |
556 | /// specified in the associated `Call` terminator in the calling function, as if assigned via | |
557 | /// `dest = move _0`. It might additionally do other things, like have side-effects in the | |
558 | /// aliasing model. | |
559 | /// | |
560 | /// If the body is a generator body, this has slightly different semantics; it instead causes a | |
561 | /// `GeneratorState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned | |
562 | /// to the return place. | |
563 | Return, | |
564 | ||
565 | /// Indicates a terminator that can never be reached. | |
566 | /// | |
567 | /// Executing this terminator is UB. | |
568 | Unreachable, | |
569 | ||
570 | /// The behavior of this statement differs significantly before and after drop elaboration. | |
571 | /// After drop elaboration, `Drop` executes the drop glue for the specified place, after which | |
572 | /// it continues execution/unwinds at the given basic blocks. It is possible that executing drop | |
573 | /// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an | |
574 | /// issue tracking if drop glue has any interesting semantics in addition to those of a function | |
575 | /// call?) | |
576 | /// | |
577 | /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the | |
578 | /// `Drop` will be executed if... | |
579 | /// | |
580 | /// **Needs clarification**: End of that sentence. This in effect should document the exact | |
581 | /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure: | |
582 | /// | |
583 | /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to | |
584 | /// > the place or one of its "parents" occurred more recently than a move out of it. This does not | |
585 | /// > consider indirect assignments. | |
586 | Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, | |
587 | ||
588 | /// Drops the place and assigns a new value to it. | |
589 | /// | |
590 | /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator; | |
591 | /// it then additionally assigns the `value` to the `place` as if by an assignment statement. | |
592 | /// This assignment occurs both in the unwind and the regular code paths. The semantics are best | |
593 | /// explained by the elaboration: | |
594 | /// | |
595 | /// ```ignore (MIR) | |
596 | /// BB0 { | |
597 | /// DropAndReplace(P <- V, goto BB1, unwind BB2) | |
598 | /// } | |
599 | /// ``` | |
600 | /// | |
601 | /// becomes | |
602 | /// | |
603 | /// ```ignore (MIR) | |
604 | /// BB0 { | |
605 | /// Drop(P, goto BB1, unwind BB2) | |
606 | /// } | |
607 | /// BB1 { | |
608 | /// // P is now uninitialized | |
609 | /// P <- V | |
610 | /// } | |
611 | /// BB2 { | |
612 | /// // P is now uninitialized -- its dtor panicked | |
613 | /// P <- V | |
614 | /// } | |
615 | /// ``` | |
616 | /// | |
617 | /// Disallowed after drop elaboration. | |
618 | DropAndReplace { | |
619 | place: Place<'tcx>, | |
620 | value: Operand<'tcx>, | |
621 | target: BasicBlock, | |
622 | unwind: Option<BasicBlock>, | |
623 | }, | |
624 | ||
625 | /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of | |
626 | /// the referred to function. The operand types must match the argument types of the function. | |
627 | /// The return place type must match the return type. The type of the `func` operand must be | |
628 | /// callable, meaning either a function pointer, a function type, or a closure type. | |
629 | /// | |
630 | /// **Needs clarification**: The exact semantics of this. Current backends rely on `move` | |
631 | /// operands not aliasing the return place. It is unclear how this is justified in MIR, see | |
632 | /// [#71117]. | |
633 | /// | |
634 | /// [#71117]: https://github.com/rust-lang/rust/issues/71117 | |
635 | Call { | |
636 | /// The function that’s being called. | |
637 | func: Operand<'tcx>, | |
638 | /// Arguments the function is called with. | |
639 | /// These are owned by the callee, which is free to modify them. | |
640 | /// This allows the memory occupied by "by-value" arguments to be | |
641 | /// reused across function calls without duplicating the contents. | |
642 | args: Vec<Operand<'tcx>>, | |
643 | /// Where the returned value will be written | |
644 | destination: Place<'tcx>, | |
645 | /// Where to go after this call returns. If none, the call necessarily diverges. | |
646 | target: Option<BasicBlock>, | |
647 | /// Cleanups to be done if the call unwinds. | |
648 | cleanup: Option<BasicBlock>, | |
649 | /// `true` if this is from a call in HIR rather than from an overloaded | |
650 | /// operator. True for overloaded function call. | |
651 | from_hir_call: bool, | |
652 | /// This `Span` is the span of the function, without the dot and receiver | |
653 | /// (e.g. `foo(a, b)` in `x.foo(a, b)` | |
654 | fn_span: Span, | |
655 | }, | |
656 | ||
657 | /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`, | |
658 | /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some | |
659 | /// unspecified constant as the function to call, all the operands stored in the `AssertMessage` | |
660 | /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not | |
661 | /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the | |
662 | /// assertion does not fail, execution continues at the specified basic block. | |
663 | Assert { | |
664 | cond: Operand<'tcx>, | |
665 | expected: bool, | |
666 | msg: AssertMessage<'tcx>, | |
667 | target: BasicBlock, | |
668 | cleanup: Option<BasicBlock>, | |
669 | }, | |
670 | ||
671 | /// Marks a suspend point. | |
672 | /// | |
673 | /// Like `Return` terminators in generator bodies, this computes `value` and then a | |
674 | /// `GeneratorState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to | |
675 | /// the return place of the function calling this one, and execution continues in the calling | |
676 | /// function. When next invoked with the same first argument, execution of this function | |
677 | /// continues at the `resume` basic block, with the second argument written to the `resume_arg` | |
678 | /// place. If the generator is dropped before then, the `drop` basic block is invoked. | |
679 | /// | |
680 | /// Not permitted in bodies that are not generator bodies, or after generator lowering. | |
681 | /// | |
682 | /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`? | |
683 | Yield { | |
684 | /// The value to return. | |
685 | value: Operand<'tcx>, | |
686 | /// Where to resume to. | |
687 | resume: BasicBlock, | |
688 | /// The place to store the resume argument in. | |
689 | resume_arg: Place<'tcx>, | |
690 | /// Cleanup to be done if the generator is dropped at this suspend point. | |
691 | drop: Option<BasicBlock>, | |
692 | }, | |
693 | ||
694 | /// Indicates the end of dropping a generator. | |
695 | /// | |
696 | /// Semantically just a `return` (from the generators drop glue). Only permitted in the same situations | |
697 | /// as `yield`. | |
698 | /// | |
699 | /// **Needs clarification**: Is that even correct? The generator drop code is always confusing | |
700 | /// to me, because it's not even really in the current body. | |
701 | /// | |
702 | /// **Needs clarification**: Are there type system constraints on these terminators? Should | |
703 | /// there be a "block type" like `cleanup` blocks for them? | |
704 | GeneratorDrop, | |
705 | ||
706 | /// A block where control flow only ever takes one real path, but borrowck needs to be more | |
707 | /// conservative. | |
708 | /// | |
709 | /// At runtime this is semantically just a goto. | |
710 | /// | |
711 | /// Disallowed after drop elaboration. | |
712 | FalseEdge { | |
713 | /// The target normal control flow will take. | |
714 | real_target: BasicBlock, | |
715 | /// A block control flow could conceptually jump to, but won't in | |
716 | /// practice. | |
717 | imaginary_target: BasicBlock, | |
718 | }, | |
719 | ||
720 | /// A terminator for blocks that only take one path in reality, but where we reserve the right | |
721 | /// to unwind in borrowck, even if it won't happen in practice. This can arise in infinite loops | |
722 | /// with no function calls for example. | |
723 | /// | |
724 | /// At runtime this is semantically just a goto. | |
725 | /// | |
726 | /// Disallowed after drop elaboration. | |
727 | FalseUnwind { | |
728 | /// The target normal control flow will take. | |
729 | real_target: BasicBlock, | |
730 | /// The imaginary cleanup block link. This particular path will never be taken | |
731 | /// in practice, but in order to avoid fragility we want to always | |
732 | /// consider it in borrowck. We don't want to accept programs which | |
733 | /// pass borrowck only when `panic=abort` or some assertions are disabled | |
734 | /// due to release vs. debug mode builds. This needs to be an `Option` because | |
735 | /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes. | |
736 | unwind: Option<BasicBlock>, | |
737 | }, | |
738 | ||
739 | /// Block ends with an inline assembly block. This is a terminator since | |
740 | /// inline assembly is allowed to diverge. | |
741 | InlineAsm { | |
742 | /// The template for the inline assembly, with placeholders. | |
743 | template: &'tcx [InlineAsmTemplatePiece], | |
744 | ||
745 | /// The operands for the inline assembly, as `Operand`s or `Place`s. | |
746 | operands: Vec<InlineAsmOperand<'tcx>>, | |
747 | ||
748 | /// Miscellaneous options for the inline assembly. | |
749 | options: InlineAsmOptions, | |
750 | ||
751 | /// Source spans for each line of the inline assembly code. These are | |
752 | /// used to map assembler errors back to the line in the source code. | |
753 | line_spans: &'tcx [Span], | |
754 | ||
755 | /// Destination block after the inline assembly returns, unless it is | |
756 | /// diverging (InlineAsmOptions::NORETURN). | |
757 | destination: Option<BasicBlock>, | |
758 | ||
759 | /// Cleanup to be done if the inline assembly unwinds. This is present | |
760 | /// if and only if InlineAsmOptions::MAY_UNWIND is set. | |
761 | cleanup: Option<BasicBlock>, | |
762 | }, | |
763 | } | |
764 | ||
765 | /// Information about an assertion failure. | |
f2b60f7d | 766 | #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] |
064997fb FG |
767 | pub enum AssertKind<O> { |
768 | BoundsCheck { len: O, index: O }, | |
769 | Overflow(BinOp, O, O), | |
770 | OverflowNeg(O), | |
771 | DivisionByZero(O), | |
772 | RemainderByZero(O), | |
773 | ResumedAfterReturn(GeneratorKind), | |
774 | ResumedAfterPanic(GeneratorKind), | |
775 | } | |
776 | ||
777 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] | |
778 | #[derive(TypeFoldable, TypeVisitable)] | |
779 | pub enum InlineAsmOperand<'tcx> { | |
780 | In { | |
781 | reg: InlineAsmRegOrRegClass, | |
782 | value: Operand<'tcx>, | |
783 | }, | |
784 | Out { | |
785 | reg: InlineAsmRegOrRegClass, | |
786 | late: bool, | |
787 | place: Option<Place<'tcx>>, | |
788 | }, | |
789 | InOut { | |
790 | reg: InlineAsmRegOrRegClass, | |
791 | late: bool, | |
792 | in_value: Operand<'tcx>, | |
793 | out_place: Option<Place<'tcx>>, | |
794 | }, | |
795 | Const { | |
796 | value: Box<Constant<'tcx>>, | |
797 | }, | |
798 | SymFn { | |
799 | value: Box<Constant<'tcx>>, | |
800 | }, | |
801 | SymStatic { | |
802 | def_id: DefId, | |
803 | }, | |
804 | } | |
805 | ||
806 | /// Type for MIR `Assert` terminator error messages. | |
807 | pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; | |
808 | ||
809 | /////////////////////////////////////////////////////////////////////////// | |
810 | // Places | |
811 | ||
812 | /// Places roughly correspond to a "location in memory." Places in MIR are the same mathematical | |
813 | /// object as places in Rust. This of course means that what exactly they are is undecided and part | |
814 | /// of the Rust memory model. However, they will likely contain at least the following pieces of | |
815 | /// information in some form: | |
816 | /// | |
817 | /// 1. The address in memory that the place refers to. | |
818 | /// 2. The provenance with which the place is being accessed. | |
819 | /// 3. The type of the place and an optional variant index. See [`PlaceTy`][super::tcx::PlaceTy]. | |
820 | /// 4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`. | |
821 | /// | |
822 | /// We'll give a description below of how all pieces of the place except for the provenance are | |
823 | /// calculated. We cannot give a description of the provenance, because that is part of the | |
824 | /// undecided aliasing model - we only include it here at all to acknowledge its existence. | |
825 | /// | |
826 | /// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has | |
827 | /// the address of the local's allocation and the type of the local. | |
828 | /// | |
829 | /// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation | |
830 | /// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation. | |
831 | /// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under | |
832 | /// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and | |
833 | /// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into | |
834 | /// the current MIR semantics in a clean way - possibly this needs some design work first. | |
835 | /// | |
836 | /// For places that are not locals, ie they have a non-empty list of projections, we define the | |
837 | /// values as a function of the parent place, that is the place with its last [`ProjectionElem`] | |
838 | /// stripped. The way this is computed of course depends on the kind of that last projection | |
839 | /// element: | |
840 | /// | |
841 | /// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the | |
842 | /// given one, and makes no other changes. A `Downcast` projection on a place with its variant | |
843 | /// index already set is not well-formed. | |
844 | /// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a | |
845 | /// place referring to one of the fields of the type. The resulting address is the parent | |
846 | /// address, plus the offset of the field. The type becomes the type of the field. If the parent | |
847 | /// was unsized and so had metadata associated with it, then the metadata is retained if the | |
848 | /// field is unsized and thrown out if it is sized. | |
849 | /// | |
850 | /// These projections are only legal for tuples, ADTs, closures, and generators. If the ADT or | |
851 | /// generator has more than one variant, the parent place's variant index must be set, indicating | |
852 | /// which variant is being used. If it has just one variant, the variant index may or may not be | |
853 | /// included - the single possible variant is inferred if it is not included. | |
2b03887a FG |
854 | /// - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the |
855 | /// given one, and makes no other changes. A `OpaqueCast` projection on any type other than an | |
856 | /// opaque type from the current crate is not well-formed. | |
064997fb FG |
857 | /// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the |
858 | /// place as described in the documentation for the `ProjectionElem`. The resulting address is | |
859 | /// the parent's address plus that offset, and the type is `T`. This is only legal if the parent | |
860 | /// place has type `[T; N]` or `[T]` (*not* `&[T]`). Since such a `T` is always sized, any | |
861 | /// resulting metadata is thrown out. | |
862 | /// - [`Subslice`](ProjectionElem::Subslice): This projection calculates an offset and a new | |
863 | /// address in a similar manner as `ConstantIndex`. It is also only legal on `[T; N]` and `[T]`. | |
864 | /// However, this yields a `Place` of type `[T]`, and additionally sets the metadata to be the | |
865 | /// length of the subslice. | |
866 | /// - [`Index`](ProjectionElem::Index): Like `ConstantIndex`, only legal on `[T; N]` or `[T]`. | |
867 | /// However, `Index` additionally takes a local from which the value of the index is computed at | |
868 | /// runtime. Computing the value of the index involves interpreting the `Local` as a | |
869 | /// `Place { local, projection: [] }`, and then computing its value as if done via | |
870 | /// [`Operand::Copy`]. The array/slice is then indexed with the resulting value. The local must | |
871 | /// have type `usize`. | |
872 | /// - [`Deref`](ProjectionElem::Deref): Derefs are the last type of projection, and the most | |
873 | /// complicated. They are only legal on parent places that are references, pointers, or `Box`. A | |
874 | /// `Deref` projection begins by loading a value from the parent place, as if by | |
875 | /// [`Operand::Copy`]. It then dereferences the resulting pointer, creating a place of the | |
876 | /// pointee's type. The resulting address is the address that was stored in the pointer. If the | |
877 | /// pointee type is unsized, the pointer additionally stored the value of the metadata. | |
878 | /// | |
879 | /// Computing a place may cause UB. One possibility is that the pointer used for a `Deref` may not | |
880 | /// be suitably aligned. Another possibility is that the place is not in bounds, meaning it does not | |
881 | /// point to an actual allocation. | |
882 | /// | |
883 | /// However, if this is actually UB and when the UB kicks in is undecided. This is being discussed | |
884 | /// in [UCG#319]. The options include that every place must obey those rules, that only some places | |
885 | /// must obey them, or that places impose no rules of their own. | |
886 | /// | |
887 | /// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319 | |
888 | /// | |
889 | /// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken | |
890 | /// advantage of by codegen (via `gep inbounds`). That is possibly subject to change. | |
f2b60f7d | 891 | #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable, TypeFoldable, TypeVisitable)] |
064997fb FG |
892 | pub struct Place<'tcx> { |
893 | pub local: Local, | |
894 | ||
895 | /// projection out of a place (access a field, deref a pointer, etc) | |
896 | pub projection: &'tcx List<PlaceElem<'tcx>>, | |
897 | } | |
898 | ||
899 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
f2b60f7d | 900 | #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] |
064997fb FG |
901 | pub enum ProjectionElem<V, T> { |
902 | Deref, | |
903 | Field(Field, T), | |
904 | /// Index into a slice/array. | |
905 | /// | |
906 | /// Note that this does not also dereference, and so it does not exactly correspond to slice | |
907 | /// indexing in Rust. In other words, in the below Rust code: | |
908 | /// | |
909 | /// ```rust | |
910 | /// let x = &[1, 2, 3, 4]; | |
911 | /// let i = 2; | |
912 | /// x[i]; | |
913 | /// ``` | |
914 | /// | |
915 | /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same | |
916 | /// thing is true of the `ConstantIndex` and `Subslice` projections below. | |
917 | Index(V), | |
918 | ||
919 | /// These indices are generated by slice patterns. Easiest to explain | |
920 | /// by example: | |
921 | /// | |
922 | /// ```ignore (illustrative) | |
923 | /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, | |
924 | /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, | |
925 | /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, | |
926 | /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, | |
927 | /// ``` | |
928 | ConstantIndex { | |
929 | /// index or -index (in Python terms), depending on from_end | |
930 | offset: u64, | |
931 | /// The thing being indexed must be at least this long. For arrays this | |
932 | /// is always the exact length. | |
933 | min_length: u64, | |
934 | /// Counting backwards from end? This is always false when indexing an | |
935 | /// array. | |
936 | from_end: bool, | |
937 | }, | |
938 | ||
939 | /// These indices are generated by slice patterns. | |
940 | /// | |
941 | /// If `from_end` is true `slice[from..slice.len() - to]`. | |
942 | /// Otherwise `array[from..to]`. | |
943 | Subslice { | |
944 | from: u64, | |
945 | to: u64, | |
946 | /// Whether `to` counts from the start or end of the array/slice. | |
947 | /// For `PlaceElem`s this is `true` if and only if the base is a slice. | |
948 | /// For `ProjectionKind`, this can also be `true` for arrays. | |
949 | from_end: bool, | |
950 | }, | |
951 | ||
952 | /// "Downcast" to a variant of an enum or a generator. | |
953 | /// | |
954 | /// The included Symbol is the name of the variant, used for printing MIR. | |
955 | Downcast(Option<Symbol>, VariantIdx), | |
2b03887a FG |
956 | |
957 | /// Like an explicit cast from an opaque type to a concrete type, but without | |
958 | /// requiring an intermediate variable. | |
959 | OpaqueCast(T), | |
064997fb FG |
960 | } |
961 | ||
962 | /// Alias for projections as they appear in places, where the base is a place | |
963 | /// and the index is a local. | |
964 | pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; | |
965 | ||
966 | /////////////////////////////////////////////////////////////////////////// | |
967 | // Operands | |
968 | ||
969 | /// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of | |
970 | /// the memory model. One proposal for a definition of values can be found [on UCG][value-def]. | |
971 | /// | |
972 | /// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md | |
973 | /// | |
974 | /// The most common way to create values is via loading a place. Loading a place is an operation | |
975 | /// which reads the memory of the place and converts it to a value. This is a fundamentally *typed* | |
976 | /// operation. The nature of the value produced depends on the type of the conversion. Furthermore, | |
977 | /// there may be other effects: if the type has a validity constraint loading the place might be UB | |
978 | /// if the validity constraint is not met. | |
979 | /// | |
980 | /// **Needs clarification:** Ralf proposes that loading a place not have side-effects. | |
981 | /// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this | |
982 | /// something we can even decide without knowing more about Rust's memory model? | |
983 | /// | |
984 | /// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri | |
985 | /// currently implements it, but it seems like this may be something to check against in the | |
986 | /// validator. | |
f2b60f7d | 987 | #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] |
064997fb FG |
988 | pub enum Operand<'tcx> { |
989 | /// Creates a value by loading the given place. | |
990 | /// | |
991 | /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there | |
992 | /// is no such requirement. | |
993 | Copy(Place<'tcx>), | |
994 | ||
995 | /// Creates a value by performing loading the place, just like the `Copy` operand. | |
996 | /// | |
997 | /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide | |
998 | /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this | |
999 | /// place without first re-initializing it. | |
1000 | /// | |
1001 | /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188 | |
1002 | Move(Place<'tcx>), | |
1003 | ||
1004 | /// Constants are already semantically values, and remain unchanged. | |
1005 | Constant(Box<Constant<'tcx>>), | |
1006 | } | |
1007 | ||
1008 | /////////////////////////////////////////////////////////////////////////// | |
1009 | // Rvalues | |
1010 | ||
1011 | /// The various kinds of rvalues that can appear in MIR. | |
1012 | /// | |
1013 | /// Not all of these are allowed at every [`MirPhase`] - when this is the case, it's stated below. | |
1014 | /// | |
1015 | /// Computing any rvalue begins by evaluating the places and operands in some order (**Needs | |
1016 | /// clarification**: Which order?). These are then used to produce a "value" - the same kind of | |
1017 | /// value that an [`Operand`] produces. | |
f2b60f7d | 1018 | #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] |
064997fb FG |
1019 | pub enum Rvalue<'tcx> { |
1020 | /// Yields the operand unchanged | |
1021 | Use(Operand<'tcx>), | |
1022 | ||
1023 | /// Creates an array where each element is the value of the operand. | |
1024 | /// | |
1025 | /// This is the cause of a bug in the case where the repetition count is zero because the value | |
1026 | /// is not dropped, see [#74836]. | |
1027 | /// | |
1028 | /// Corresponds to source code like `[x; 32]`. | |
1029 | /// | |
1030 | /// [#74836]: https://github.com/rust-lang/rust/issues/74836 | |
1031 | Repeat(Operand<'tcx>, ty::Const<'tcx>), | |
1032 | ||
1033 | /// Creates a reference of the indicated kind to the place. | |
1034 | /// | |
1035 | /// There is not much to document here, because besides the obvious parts the semantics of this | |
1036 | /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing | |
1037 | /// exactly what the behavior of this operation should be. | |
1038 | /// | |
1039 | /// `Shallow` borrows are disallowed after drop lowering. | |
1040 | Ref(Region<'tcx>, BorrowKind, Place<'tcx>), | |
1041 | ||
1042 | /// Creates a pointer/reference to the given thread local. | |
1043 | /// | |
1044 | /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a | |
1045 | /// `*const T`, and if neither of those apply a `&T`. | |
1046 | /// | |
1047 | /// **Note:** This is a runtime operation that actually executes code and is in this sense more | |
1048 | /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to | |
1049 | /// SIGILL for some reason that I (JakobDegen) never got a chance to look into. | |
1050 | /// | |
1051 | /// **Needs clarification**: Are there weird additional semantics here related to the runtime | |
1052 | /// nature of this operation? | |
1053 | ThreadLocalRef(DefId), | |
1054 | ||
1055 | /// Creates a pointer with the indicated mutability to the place. | |
1056 | /// | |
1057 | /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like | |
1058 | /// `&raw v` or `addr_of!(v)`. | |
1059 | /// | |
1060 | /// Like with references, the semantics of this operation are heavily dependent on the aliasing | |
1061 | /// model. | |
1062 | AddressOf(Mutability, Place<'tcx>), | |
1063 | ||
1064 | /// Yields the length of the place, as a `usize`. | |
1065 | /// | |
1066 | /// If the type of the place is an array, this is the array length. For slices (`[T]`, not | |
1067 | /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is | |
1068 | /// ill-formed for places of other types. | |
1069 | Len(Place<'tcx>), | |
1070 | ||
1071 | /// Performs essentially all of the casts that can be performed via `as`. | |
1072 | /// | |
1073 | /// This allows for casts from/to a variety of types. | |
1074 | /// | |
1075 | /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why | |
1076 | /// `ArrayToPointer` and `MutToConstPointer` are special. | |
1077 | Cast(CastKind, Operand<'tcx>, Ty<'tcx>), | |
1078 | ||
1079 | /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second | |
1080 | /// parameter may be a `usize` as well. | |
1081 | /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, | |
1082 | /// raw pointers, or function pointers and return a `bool`. The types of the operands must be | |
1083 | /// matching, up to the usual caveat of the lifetimes in function pointers. | |
1084 | /// * Left and right shift operations accept signed or unsigned integers not necessarily of the | |
1085 | /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is | |
1086 | /// truncated as needed. | |
1087 | /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching | |
1088 | /// types and return a value of that type. | |
1089 | /// * The remaining operations accept signed integers, unsigned integers, or floats with | |
1090 | /// matching types and return a value of that type. | |
1091 | BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), | |
1092 | ||
1093 | /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. | |
1094 | /// | |
1095 | /// When overflow checking is disabled and we are generating run-time code, the error condition | |
1096 | /// is false. Otherwise, and always during CTFE, the error condition is determined as described | |
1097 | /// below. | |
1098 | /// | |
1099 | /// For addition, subtraction, and multiplication on integers the error condition is set when | |
1100 | /// the infinite precision result would be unequal to the actual result. | |
1101 | /// | |
1102 | /// For shift operations on integers the error condition is set when the value of right-hand | |
1103 | /// side is greater than or equal to the number of bits in the type of the left-hand side, or | |
1104 | /// when the value of right-hand side is negative. | |
1105 | /// | |
1106 | /// Other combinations of types and operators are unsupported. | |
1107 | CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), | |
1108 | ||
1109 | /// Computes a value as described by the operation. | |
1110 | NullaryOp(NullOp, Ty<'tcx>), | |
1111 | ||
1112 | /// Exactly like `BinaryOp`, but less operands. | |
1113 | /// | |
1114 | /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; | |
1115 | /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds | |
1116 | /// return a value with the same type as their operand. | |
1117 | UnaryOp(UnOp, Operand<'tcx>), | |
1118 | ||
1119 | /// Computes the discriminant of the place, returning it as an integer of type | |
1120 | /// [`discriminant_ty`]. Returns zero for types without discriminant. | |
1121 | /// | |
1122 | /// The validity requirements for the underlying value are undecided for this rvalue, see | |
1123 | /// [#91095]. Note too that the value of the discriminant is not the same thing as the | |
1124 | /// variant index; use [`discriminant_for_variant`] to convert. | |
1125 | /// | |
1126 | /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty | |
1127 | /// [#91095]: https://github.com/rust-lang/rust/issues/91095 | |
1128 | /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant | |
1129 | Discriminant(Place<'tcx>), | |
1130 | ||
1131 | /// Creates an aggregate value, like a tuple or struct. | |
1132 | /// | |
1133 | /// This is needed because dataflow analysis needs to distinguish | |
1134 | /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo` | |
1135 | /// has a destructor. | |
1136 | /// | |
1137 | /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After | |
1138 | /// generator lowering, `Generator` aggregate kinds are disallowed too. | |
1139 | Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), | |
1140 | ||
1141 | /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. | |
1142 | /// | |
1143 | /// This is different from a normal transmute because dataflow analysis will treat the box as | |
1144 | /// initialized but its content as uninitialized. Like other pointer casts, this in general | |
1145 | /// affects alias analysis. | |
1146 | ShallowInitBox(Operand<'tcx>, Ty<'tcx>), | |
1147 | ||
1148 | /// A CopyForDeref is equivalent to a read from a place at the | |
1149 | /// codegen level, but is treated specially by drop elaboration. When such a read happens, it | |
1150 | /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator) | |
1151 | /// that the only use of the returned value is a deref operation, immediately | |
1152 | /// followed by one or more projections. Drop elaboration treats this rvalue as if the | |
1153 | /// read never happened and just projects further. This allows simplifying various MIR | |
1154 | /// optimizations and codegen backends that previously had to handle deref operations anywhere | |
1155 | /// in a place. | |
1156 | CopyForDeref(Place<'tcx>), | |
1157 | } | |
1158 | ||
1159 | #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] | |
1160 | pub enum CastKind { | |
1161 | /// An exposing pointer to address cast. A cast between a pointer and an integer type, or | |
1162 | /// between a function pointer and an integer type. | |
1163 | /// See the docs on `expose_addr` for more details. | |
1164 | PointerExposeAddress, | |
1165 | /// An address-to-pointer cast that picks up an exposed provenance. | |
1166 | /// See the docs on `from_exposed_addr` for more details. | |
1167 | PointerFromExposedAddress, | |
1168 | /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are | |
1169 | /// translated into `&raw mut/const *r`, i.e., they are not actually casts. | |
1170 | Pointer(PointerCast), | |
f2b60f7d FG |
1171 | /// Cast into a dyn* object. |
1172 | DynStar, | |
2b03887a FG |
1173 | IntToInt, |
1174 | FloatToInt, | |
1175 | FloatToFloat, | |
1176 | IntToFloat, | |
1177 | PtrToPtr, | |
1178 | FnPtrToPtr, | |
064997fb FG |
1179 | } |
1180 | ||
1181 | #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] | |
f2b60f7d | 1182 | #[derive(TypeFoldable, TypeVisitable)] |
064997fb FG |
1183 | pub enum AggregateKind<'tcx> { |
1184 | /// The type is of the element | |
1185 | Array(Ty<'tcx>), | |
1186 | Tuple, | |
1187 | ||
1188 | /// The second field is the variant index. It's equal to 0 for struct | |
1189 | /// and union expressions. The fourth field is | |
1190 | /// active field number and is present only for union expressions | |
1191 | /// -- e.g., for a union expression `SomeUnion { c: .. }`, the | |
1192 | /// active field index would identity the field `c` | |
1193 | Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), | |
1194 | ||
1195 | // Note: We can use LocalDefId since closures and generators a deaggregated | |
1196 | // before codegen. | |
1197 | Closure(LocalDefId, SubstsRef<'tcx>), | |
1198 | Generator(LocalDefId, SubstsRef<'tcx>, hir::Movability), | |
1199 | } | |
1200 | ||
1201 | #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] | |
1202 | pub enum NullOp { | |
1203 | /// Returns the size of a value of that type | |
1204 | SizeOf, | |
1205 | /// Returns the minimum alignment of a type | |
1206 | AlignOf, | |
1207 | } | |
1208 | ||
487cf647 FG |
1209 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
1210 | #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] | |
064997fb FG |
1211 | pub enum UnOp { |
1212 | /// The `!` operator for logical inversion | |
1213 | Not, | |
1214 | /// The `-` operator for negation | |
1215 | Neg, | |
1216 | } | |
1217 | ||
487cf647 FG |
1218 | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] |
1219 | #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] | |
064997fb FG |
1220 | pub enum BinOp { |
1221 | /// The `+` operator (addition) | |
1222 | Add, | |
1223 | /// The `-` operator (subtraction) | |
1224 | Sub, | |
1225 | /// The `*` operator (multiplication) | |
1226 | Mul, | |
1227 | /// The `/` operator (division) | |
1228 | /// | |
1229 | /// Division by zero is UB, because the compiler should have inserted checks | |
1230 | /// prior to this. | |
1231 | Div, | |
1232 | /// The `%` operator (modulus) | |
1233 | /// | |
1234 | /// Using zero as the modulus (second operand) is UB, because the compiler | |
1235 | /// should have inserted checks prior to this. | |
1236 | Rem, | |
1237 | /// The `^` operator (bitwise xor) | |
1238 | BitXor, | |
1239 | /// The `&` operator (bitwise and) | |
1240 | BitAnd, | |
1241 | /// The `|` operator (bitwise or) | |
1242 | BitOr, | |
1243 | /// The `<<` operator (shift left) | |
1244 | /// | |
1245 | /// The offset is truncated to the size of the first operand before shifting. | |
1246 | Shl, | |
1247 | /// The `>>` operator (shift right) | |
1248 | /// | |
1249 | /// The offset is truncated to the size of the first operand before shifting. | |
1250 | Shr, | |
1251 | /// The `==` operator (equality) | |
1252 | Eq, | |
1253 | /// The `<` operator (less than) | |
1254 | Lt, | |
1255 | /// The `<=` operator (less than or equal to) | |
1256 | Le, | |
1257 | /// The `!=` operator (not equal to) | |
1258 | Ne, | |
1259 | /// The `>=` operator (greater than or equal to) | |
1260 | Ge, | |
1261 | /// The `>` operator (greater than) | |
1262 | Gt, | |
1263 | /// The `ptr.offset` operator | |
1264 | Offset, | |
1265 | } | |
1266 | ||
1267 | // Some nodes are used a lot. Make sure they don't unintentionally get bigger. | |
1268 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] | |
1269 | mod size_asserts { | |
1270 | use super::*; | |
2b03887a | 1271 | // tidy-alphabetical-start |
f2b60f7d | 1272 | static_assert_size!(AggregateKind<'_>, 40); |
064997fb FG |
1273 | static_assert_size!(Operand<'_>, 24); |
1274 | static_assert_size!(Place<'_>, 16); | |
1275 | static_assert_size!(PlaceElem<'_>, 24); | |
1276 | static_assert_size!(Rvalue<'_>, 40); | |
2b03887a | 1277 | // tidy-alphabetical-end |
064997fb | 1278 | } |