]>
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 | /// | |
f25598a0 FG |
323 | /// For code that is not specific to stacked borrows, you should consider retags to read and |
324 | /// modify the place in an opaque way. | |
325 | /// | |
326 | /// Only `RetagKind::Default` and `RetagKind::FnEntry` are permitted. | |
064997fb FG |
327 | Retag(RetagKind, Box<Place<'tcx>>), |
328 | ||
329 | /// Encodes a user's type ascription. These need to be preserved | |
330 | /// intact so that NLL can respect them. For example: | |
331 | /// ```ignore (illustrative) | |
332 | /// let a: T = y; | |
333 | /// ``` | |
334 | /// The effect of this annotation is to relate the type `T_y` of the place `y` | |
335 | /// to the user-given type `T`. The effect depends on the specified variance: | |
336 | /// | |
337 | /// - `Covariant` -- requires that `T_y <: T` | |
338 | /// - `Contravariant` -- requires that `T_y :> T` | |
339 | /// - `Invariant` -- requires that `T_y == T` | |
340 | /// - `Bivariant` -- no effect | |
341 | /// | |
342 | /// When executed at runtime this is a nop. | |
343 | /// | |
344 | /// Disallowed after drop elaboration. | |
345 | AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), | |
346 | ||
347 | /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A | |
348 | /// `Coverage` statement carries metadata about the coverage region, used to inject a coverage | |
349 | /// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates | |
350 | /// executable code, to increment a counter variable at runtime, each time the code region is | |
351 | /// executed. | |
352 | Coverage(Box<Coverage>), | |
353 | ||
f2b60f7d FG |
354 | /// Denotes a call to an intrinsic that does not require an unwind path and always returns. |
355 | /// This avoids adding a new block and a terminator for simple intrinsics. | |
356 | Intrinsic(Box<NonDivergingIntrinsic<'tcx>>), | |
357 | ||
358 | /// No-op. Useful for deleting instructions without affecting statement indices. | |
359 | Nop, | |
360 | } | |
361 | ||
362 | #[derive( | |
363 | Clone, | |
364 | TyEncodable, | |
365 | TyDecodable, | |
366 | Debug, | |
367 | PartialEq, | |
368 | Hash, | |
369 | HashStable, | |
370 | TypeFoldable, | |
371 | TypeVisitable | |
372 | )] | |
373 | pub enum NonDivergingIntrinsic<'tcx> { | |
374 | /// Denotes a call to the intrinsic function `assume`. | |
375 | /// | |
376 | /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its | |
377 | /// computation to infer information about other variables. So if the boolean came from a | |
378 | /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks. | |
379 | /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`. | |
380 | Assume(Operand<'tcx>), | |
381 | ||
064997fb FG |
382 | /// Denotes a call to the intrinsic function `copy_nonoverlapping`. |
383 | /// | |
384 | /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer, | |
385 | /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and | |
386 | /// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of | |
f2b60f7d | 387 | /// the `src` place are copied to the contiguous range of bytes beginning with the first byte |
064997fb FG |
388 | /// of `dest`. |
389 | /// | |
390 | /// **Needs clarification**: In what order are operands computed and dereferenced? It should | |
391 | /// probably match the order for assignment, but that is also undecided. | |
392 | /// | |
393 | /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved? | |
394 | /// I vaguely remember Ralf saying somewhere that he thought it should not be. | |
f2b60f7d FG |
395 | CopyNonOverlapping(CopyNonOverlapping<'tcx>), |
396 | } | |
064997fb | 397 | |
f2b60f7d FG |
398 | impl std::fmt::Display for NonDivergingIntrinsic<'_> { |
399 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
400 | match self { | |
401 | Self::Assume(op) => write!(f, "assume({op:?})"), | |
402 | Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { | |
403 | write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})") | |
404 | } | |
405 | } | |
406 | } | |
064997fb FG |
407 | } |
408 | ||
409 | /// Describes what kind of retag is to be performed. | |
410 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)] | |
411 | #[rustc_pass_by_value] | |
412 | pub enum RetagKind { | |
487cf647 | 413 | /// The initial retag of arguments when entering a function. |
064997fb FG |
414 | FnEntry, |
415 | /// Retag preparing for a two-phase borrow. | |
416 | TwoPhase, | |
417 | /// Retagging raw pointers. | |
418 | Raw, | |
419 | /// A "normal" retag. | |
420 | Default, | |
421 | } | |
422 | ||
423 | /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. | |
424 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)] | |
425 | pub enum FakeReadCause { | |
426 | /// Inject a fake read of the borrowed input at the end of each guards | |
427 | /// code. | |
428 | /// | |
429 | /// This should ensure that you cannot change the variant for an enum while | |
430 | /// you are in the midst of matching on it. | |
431 | ForMatchGuard, | |
432 | ||
433 | /// `let x: !; match x {}` doesn't generate any read of x so we need to | |
434 | /// generate a read of x to check that it is initialized and safe. | |
435 | /// | |
436 | /// If a closure pattern matches a Place starting with an Upvar, then we introduce a | |
437 | /// FakeRead for that Place outside the closure, in such a case this option would be | |
438 | /// Some(closure_def_id). | |
439 | /// Otherwise, the value of the optional LocalDefId will be None. | |
440 | // | |
f2b60f7d | 441 | // We can use LocalDefId here since fake read statements are removed |
064997fb FG |
442 | // before codegen in the `CleanupNonCodegenStatements` pass. |
443 | ForMatchedPlace(Option<LocalDefId>), | |
444 | ||
445 | /// A fake read of the RefWithinGuard version of a bind-by-value variable | |
446 | /// in a match guard to ensure that its value hasn't change by the time | |
447 | /// we create the OutsideGuard version. | |
448 | ForGuardBinding, | |
449 | ||
450 | /// Officially, the semantics of | |
451 | /// | |
452 | /// `let pattern = <expr>;` | |
453 | /// | |
454 | /// is that `<expr>` is evaluated into a temporary and then this temporary is | |
455 | /// into the pattern. | |
456 | /// | |
457 | /// However, if we see the simple pattern `let var = <expr>`, we optimize this to | |
458 | /// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable, | |
459 | /// but in some cases it can affect the borrow checker, as in #53695. | |
460 | /// Therefore, we insert a "fake read" here to ensure that we get | |
461 | /// appropriate errors. | |
462 | /// | |
463 | /// If a closure pattern matches a Place starting with an Upvar, then we introduce a | |
464 | /// FakeRead for that Place outside the closure, in such a case this option would be | |
465 | /// Some(closure_def_id). | |
466 | /// Otherwise, the value of the optional DefId will be None. | |
467 | ForLet(Option<LocalDefId>), | |
468 | ||
469 | /// If we have an index expression like | |
470 | /// | |
471 | /// (*x)[1][{ x = y; 4}] | |
472 | /// | |
473 | /// then the first bounds check is invalidated when we evaluate the second | |
474 | /// index expression. Thus we create a fake borrow of `x` across the second | |
475 | /// indexer, which will cause a borrow check error. | |
476 | ForIndex, | |
477 | } | |
478 | ||
479 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] | |
480 | #[derive(TypeFoldable, TypeVisitable)] | |
481 | pub struct Coverage { | |
482 | pub kind: CoverageKind, | |
483 | pub code_region: Option<CodeRegion>, | |
484 | } | |
485 | ||
486 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] | |
487 | #[derive(TypeFoldable, TypeVisitable)] | |
488 | pub struct CopyNonOverlapping<'tcx> { | |
489 | pub src: Operand<'tcx>, | |
490 | pub dst: Operand<'tcx>, | |
491 | /// Number of elements to copy from src to dest, not bytes. | |
492 | pub count: Operand<'tcx>, | |
493 | } | |
494 | ||
495 | /////////////////////////////////////////////////////////////////////////// | |
496 | // Terminators | |
497 | ||
498 | /// The various kinds of terminators, representing ways of exiting from a basic block. | |
499 | /// | |
500 | /// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the | |
501 | /// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such | |
502 | /// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then | |
503 | /// once the current function is reached, execution continues at the given basic block, if any. If | |
504 | /// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is | |
505 | /// equivalent to the execution of a `Resume` terminator. | |
506 | /// | |
507 | /// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup` | |
508 | /// basic blocks have a couple restrictions: | |
509 | /// 1. All `cleanup` fields in them must be `None`. | |
510 | /// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are. | |
511 | /// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks | |
512 | /// must also be `cleanup`. This is a part of the type system and checked statically, so it is | |
513 | /// still an error to have such an edge in the CFG even if it's known that it won't be taken at | |
514 | /// runtime. | |
f25598a0 FG |
515 | /// 4. The control flow between cleanup blocks must look like an upside down tree. Roughly |
516 | /// speaking, this means that control flow that looks like a V is allowed, while control flow | |
517 | /// that looks like a W is not. This is necessary to ensure that landing pad information can be | |
518 | /// correctly codegened on MSVC. More precisely: | |
519 | /// | |
520 | /// Begin with the standard control flow graph `G`. Modify `G` as follows: for any two cleanup | |
521 | /// vertices `u` and `v` such that `u` dominates `v`, contract `u` and `v` into a single vertex, | |
522 | /// deleting self edges and duplicate edges in the process. Now remove all vertices from `G` | |
523 | /// that are not cleanup vertices or are not reachable. The resulting graph must be an inverted | |
524 | /// tree, that is each vertex may have at most one successor and there may be no cycles. | |
f2b60f7d | 525 | #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] |
064997fb FG |
526 | pub enum TerminatorKind<'tcx> { |
527 | /// Block has one successor; we continue execution there. | |
528 | Goto { target: BasicBlock }, | |
529 | ||
530 | /// Switches based on the computed value. | |
531 | /// | |
532 | /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned | |
533 | /// integer, char, or bool, and must match the given type. Then, if the list of switch targets | |
534 | /// contains the computed value, continues execution at the associated basic block. Otherwise, | |
535 | /// continues execution at the "otherwise" basic block. | |
536 | /// | |
537 | /// Target values may not appear more than once. | |
538 | SwitchInt { | |
539 | /// The discriminant value being tested. | |
540 | discr: Operand<'tcx>, | |
064997fb FG |
541 | targets: SwitchTargets, |
542 | }, | |
543 | ||
544 | /// Indicates that the landing pad is finished and that the process should continue unwinding. | |
545 | /// | |
546 | /// Like a return, this marks the end of this invocation of the function. | |
547 | /// | |
548 | /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after | |
549 | /// deaggregation runs. | |
550 | Resume, | |
551 | ||
552 | /// Indicates that the landing pad is finished and that the process should abort. | |
553 | /// | |
554 | /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in | |
555 | /// cleanup blocks. | |
556 | Abort, | |
557 | ||
558 | /// Returns from the function. | |
559 | /// | |
560 | /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very | |
561 | /// likely at least assigns the value currently in the return place (`_0`) to the place | |
562 | /// specified in the associated `Call` terminator in the calling function, as if assigned via | |
563 | /// `dest = move _0`. It might additionally do other things, like have side-effects in the | |
564 | /// aliasing model. | |
565 | /// | |
566 | /// If the body is a generator body, this has slightly different semantics; it instead causes a | |
567 | /// `GeneratorState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned | |
568 | /// to the return place. | |
569 | Return, | |
570 | ||
571 | /// Indicates a terminator that can never be reached. | |
572 | /// | |
573 | /// Executing this terminator is UB. | |
574 | Unreachable, | |
575 | ||
576 | /// The behavior of this statement differs significantly before and after drop elaboration. | |
f25598a0 FG |
577 | /// |
578 | /// After drop elaboration: `Drop` terminators are a complete nop for types that have no drop | |
579 | /// glue. For other types, `Drop` terminators behave exactly like a call to | |
580 | /// `core::mem::drop_in_place` with a pointer to the given place. | |
581 | /// | |
582 | /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, | |
583 | /// the `Drop` will be executed if... | |
064997fb FG |
584 | /// |
585 | /// **Needs clarification**: End of that sentence. This in effect should document the exact | |
586 | /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure: | |
587 | /// | |
588 | /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to | |
589 | /// > the place or one of its "parents" occurred more recently than a move out of it. This does not | |
590 | /// > consider indirect assignments. | |
591 | Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, | |
592 | ||
593 | /// Drops the place and assigns a new value to it. | |
594 | /// | |
595 | /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator; | |
596 | /// it then additionally assigns the `value` to the `place` as if by an assignment statement. | |
597 | /// This assignment occurs both in the unwind and the regular code paths. The semantics are best | |
598 | /// explained by the elaboration: | |
599 | /// | |
600 | /// ```ignore (MIR) | |
601 | /// BB0 { | |
602 | /// DropAndReplace(P <- V, goto BB1, unwind BB2) | |
603 | /// } | |
604 | /// ``` | |
605 | /// | |
606 | /// becomes | |
607 | /// | |
608 | /// ```ignore (MIR) | |
609 | /// BB0 { | |
610 | /// Drop(P, goto BB1, unwind BB2) | |
611 | /// } | |
612 | /// BB1 { | |
613 | /// // P is now uninitialized | |
614 | /// P <- V | |
615 | /// } | |
616 | /// BB2 { | |
617 | /// // P is now uninitialized -- its dtor panicked | |
618 | /// P <- V | |
619 | /// } | |
620 | /// ``` | |
621 | /// | |
622 | /// Disallowed after drop elaboration. | |
623 | DropAndReplace { | |
624 | place: Place<'tcx>, | |
625 | value: Operand<'tcx>, | |
626 | target: BasicBlock, | |
627 | unwind: Option<BasicBlock>, | |
628 | }, | |
629 | ||
630 | /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of | |
631 | /// the referred to function. The operand types must match the argument types of the function. | |
632 | /// The return place type must match the return type. The type of the `func` operand must be | |
633 | /// callable, meaning either a function pointer, a function type, or a closure type. | |
634 | /// | |
635 | /// **Needs clarification**: The exact semantics of this. Current backends rely on `move` | |
636 | /// operands not aliasing the return place. It is unclear how this is justified in MIR, see | |
637 | /// [#71117]. | |
638 | /// | |
639 | /// [#71117]: https://github.com/rust-lang/rust/issues/71117 | |
640 | Call { | |
641 | /// The function that’s being called. | |
642 | func: Operand<'tcx>, | |
643 | /// Arguments the function is called with. | |
644 | /// These are owned by the callee, which is free to modify them. | |
645 | /// This allows the memory occupied by "by-value" arguments to be | |
646 | /// reused across function calls without duplicating the contents. | |
647 | args: Vec<Operand<'tcx>>, | |
648 | /// Where the returned value will be written | |
649 | destination: Place<'tcx>, | |
650 | /// Where to go after this call returns. If none, the call necessarily diverges. | |
651 | target: Option<BasicBlock>, | |
652 | /// Cleanups to be done if the call unwinds. | |
653 | cleanup: Option<BasicBlock>, | |
654 | /// `true` if this is from a call in HIR rather than from an overloaded | |
655 | /// operator. True for overloaded function call. | |
656 | from_hir_call: bool, | |
657 | /// This `Span` is the span of the function, without the dot and receiver | |
658 | /// (e.g. `foo(a, b)` in `x.foo(a, b)` | |
659 | fn_span: Span, | |
660 | }, | |
661 | ||
662 | /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`, | |
663 | /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some | |
664 | /// unspecified constant as the function to call, all the operands stored in the `AssertMessage` | |
665 | /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not | |
666 | /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the | |
667 | /// assertion does not fail, execution continues at the specified basic block. | |
668 | Assert { | |
669 | cond: Operand<'tcx>, | |
670 | expected: bool, | |
671 | msg: AssertMessage<'tcx>, | |
672 | target: BasicBlock, | |
673 | cleanup: Option<BasicBlock>, | |
674 | }, | |
675 | ||
676 | /// Marks a suspend point. | |
677 | /// | |
678 | /// Like `Return` terminators in generator bodies, this computes `value` and then a | |
679 | /// `GeneratorState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to | |
680 | /// the return place of the function calling this one, and execution continues in the calling | |
681 | /// function. When next invoked with the same first argument, execution of this function | |
682 | /// continues at the `resume` basic block, with the second argument written to the `resume_arg` | |
683 | /// place. If the generator is dropped before then, the `drop` basic block is invoked. | |
684 | /// | |
685 | /// Not permitted in bodies that are not generator bodies, or after generator lowering. | |
686 | /// | |
687 | /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`? | |
688 | Yield { | |
689 | /// The value to return. | |
690 | value: Operand<'tcx>, | |
691 | /// Where to resume to. | |
692 | resume: BasicBlock, | |
693 | /// The place to store the resume argument in. | |
694 | resume_arg: Place<'tcx>, | |
695 | /// Cleanup to be done if the generator is dropped at this suspend point. | |
696 | drop: Option<BasicBlock>, | |
697 | }, | |
698 | ||
699 | /// Indicates the end of dropping a generator. | |
700 | /// | |
701 | /// Semantically just a `return` (from the generators drop glue). Only permitted in the same situations | |
702 | /// as `yield`. | |
703 | /// | |
704 | /// **Needs clarification**: Is that even correct? The generator drop code is always confusing | |
705 | /// to me, because it's not even really in the current body. | |
706 | /// | |
707 | /// **Needs clarification**: Are there type system constraints on these terminators? Should | |
708 | /// there be a "block type" like `cleanup` blocks for them? | |
709 | GeneratorDrop, | |
710 | ||
711 | /// A block where control flow only ever takes one real path, but borrowck needs to be more | |
712 | /// conservative. | |
713 | /// | |
714 | /// At runtime this is semantically just a goto. | |
715 | /// | |
716 | /// Disallowed after drop elaboration. | |
717 | FalseEdge { | |
718 | /// The target normal control flow will take. | |
719 | real_target: BasicBlock, | |
720 | /// A block control flow could conceptually jump to, but won't in | |
721 | /// practice. | |
722 | imaginary_target: BasicBlock, | |
723 | }, | |
724 | ||
725 | /// A terminator for blocks that only take one path in reality, but where we reserve the right | |
726 | /// to unwind in borrowck, even if it won't happen in practice. This can arise in infinite loops | |
727 | /// with no function calls for example. | |
728 | /// | |
729 | /// At runtime this is semantically just a goto. | |
730 | /// | |
731 | /// Disallowed after drop elaboration. | |
732 | FalseUnwind { | |
733 | /// The target normal control flow will take. | |
734 | real_target: BasicBlock, | |
735 | /// The imaginary cleanup block link. This particular path will never be taken | |
736 | /// in practice, but in order to avoid fragility we want to always | |
737 | /// consider it in borrowck. We don't want to accept programs which | |
738 | /// pass borrowck only when `panic=abort` or some assertions are disabled | |
739 | /// due to release vs. debug mode builds. This needs to be an `Option` because | |
740 | /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes. | |
741 | unwind: Option<BasicBlock>, | |
742 | }, | |
743 | ||
744 | /// Block ends with an inline assembly block. This is a terminator since | |
745 | /// inline assembly is allowed to diverge. | |
746 | InlineAsm { | |
747 | /// The template for the inline assembly, with placeholders. | |
748 | template: &'tcx [InlineAsmTemplatePiece], | |
749 | ||
750 | /// The operands for the inline assembly, as `Operand`s or `Place`s. | |
751 | operands: Vec<InlineAsmOperand<'tcx>>, | |
752 | ||
753 | /// Miscellaneous options for the inline assembly. | |
754 | options: InlineAsmOptions, | |
755 | ||
756 | /// Source spans for each line of the inline assembly code. These are | |
757 | /// used to map assembler errors back to the line in the source code. | |
758 | line_spans: &'tcx [Span], | |
759 | ||
760 | /// Destination block after the inline assembly returns, unless it is | |
761 | /// diverging (InlineAsmOptions::NORETURN). | |
762 | destination: Option<BasicBlock>, | |
763 | ||
764 | /// Cleanup to be done if the inline assembly unwinds. This is present | |
765 | /// if and only if InlineAsmOptions::MAY_UNWIND is set. | |
766 | cleanup: Option<BasicBlock>, | |
767 | }, | |
768 | } | |
769 | ||
770 | /// Information about an assertion failure. | |
f2b60f7d | 771 | #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] |
064997fb FG |
772 | pub enum AssertKind<O> { |
773 | BoundsCheck { len: O, index: O }, | |
774 | Overflow(BinOp, O, O), | |
775 | OverflowNeg(O), | |
776 | DivisionByZero(O), | |
777 | RemainderByZero(O), | |
778 | ResumedAfterReturn(GeneratorKind), | |
779 | ResumedAfterPanic(GeneratorKind), | |
780 | } | |
781 | ||
782 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] | |
783 | #[derive(TypeFoldable, TypeVisitable)] | |
784 | pub enum InlineAsmOperand<'tcx> { | |
785 | In { | |
786 | reg: InlineAsmRegOrRegClass, | |
787 | value: Operand<'tcx>, | |
788 | }, | |
789 | Out { | |
790 | reg: InlineAsmRegOrRegClass, | |
791 | late: bool, | |
792 | place: Option<Place<'tcx>>, | |
793 | }, | |
794 | InOut { | |
795 | reg: InlineAsmRegOrRegClass, | |
796 | late: bool, | |
797 | in_value: Operand<'tcx>, | |
798 | out_place: Option<Place<'tcx>>, | |
799 | }, | |
800 | Const { | |
801 | value: Box<Constant<'tcx>>, | |
802 | }, | |
803 | SymFn { | |
804 | value: Box<Constant<'tcx>>, | |
805 | }, | |
806 | SymStatic { | |
807 | def_id: DefId, | |
808 | }, | |
809 | } | |
810 | ||
811 | /// Type for MIR `Assert` terminator error messages. | |
812 | pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; | |
813 | ||
814 | /////////////////////////////////////////////////////////////////////////// | |
815 | // Places | |
816 | ||
817 | /// Places roughly correspond to a "location in memory." Places in MIR are the same mathematical | |
818 | /// object as places in Rust. This of course means that what exactly they are is undecided and part | |
819 | /// of the Rust memory model. However, they will likely contain at least the following pieces of | |
820 | /// information in some form: | |
821 | /// | |
822 | /// 1. The address in memory that the place refers to. | |
823 | /// 2. The provenance with which the place is being accessed. | |
824 | /// 3. The type of the place and an optional variant index. See [`PlaceTy`][super::tcx::PlaceTy]. | |
825 | /// 4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`. | |
826 | /// | |
827 | /// We'll give a description below of how all pieces of the place except for the provenance are | |
828 | /// calculated. We cannot give a description of the provenance, because that is part of the | |
829 | /// undecided aliasing model - we only include it here at all to acknowledge its existence. | |
830 | /// | |
831 | /// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has | |
832 | /// the address of the local's allocation and the type of the local. | |
833 | /// | |
834 | /// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation | |
835 | /// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation. | |
836 | /// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under | |
837 | /// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and | |
838 | /// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into | |
839 | /// the current MIR semantics in a clean way - possibly this needs some design work first. | |
840 | /// | |
841 | /// For places that are not locals, ie they have a non-empty list of projections, we define the | |
842 | /// values as a function of the parent place, that is the place with its last [`ProjectionElem`] | |
843 | /// stripped. The way this is computed of course depends on the kind of that last projection | |
844 | /// element: | |
845 | /// | |
846 | /// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the | |
847 | /// given one, and makes no other changes. A `Downcast` projection on a place with its variant | |
848 | /// index already set is not well-formed. | |
849 | /// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a | |
850 | /// place referring to one of the fields of the type. The resulting address is the parent | |
851 | /// address, plus the offset of the field. The type becomes the type of the field. If the parent | |
852 | /// was unsized and so had metadata associated with it, then the metadata is retained if the | |
853 | /// field is unsized and thrown out if it is sized. | |
854 | /// | |
855 | /// These projections are only legal for tuples, ADTs, closures, and generators. If the ADT or | |
856 | /// generator has more than one variant, the parent place's variant index must be set, indicating | |
857 | /// which variant is being used. If it has just one variant, the variant index may or may not be | |
858 | /// included - the single possible variant is inferred if it is not included. | |
2b03887a FG |
859 | /// - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the |
860 | /// given one, and makes no other changes. A `OpaqueCast` projection on any type other than an | |
861 | /// opaque type from the current crate is not well-formed. | |
064997fb FG |
862 | /// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the |
863 | /// place as described in the documentation for the `ProjectionElem`. The resulting address is | |
864 | /// the parent's address plus that offset, and the type is `T`. This is only legal if the parent | |
865 | /// place has type `[T; N]` or `[T]` (*not* `&[T]`). Since such a `T` is always sized, any | |
866 | /// resulting metadata is thrown out. | |
867 | /// - [`Subslice`](ProjectionElem::Subslice): This projection calculates an offset and a new | |
868 | /// address in a similar manner as `ConstantIndex`. It is also only legal on `[T; N]` and `[T]`. | |
869 | /// However, this yields a `Place` of type `[T]`, and additionally sets the metadata to be the | |
870 | /// length of the subslice. | |
871 | /// - [`Index`](ProjectionElem::Index): Like `ConstantIndex`, only legal on `[T; N]` or `[T]`. | |
872 | /// However, `Index` additionally takes a local from which the value of the index is computed at | |
873 | /// runtime. Computing the value of the index involves interpreting the `Local` as a | |
874 | /// `Place { local, projection: [] }`, and then computing its value as if done via | |
875 | /// [`Operand::Copy`]. The array/slice is then indexed with the resulting value. The local must | |
876 | /// have type `usize`. | |
877 | /// - [`Deref`](ProjectionElem::Deref): Derefs are the last type of projection, and the most | |
878 | /// complicated. They are only legal on parent places that are references, pointers, or `Box`. A | |
879 | /// `Deref` projection begins by loading a value from the parent place, as if by | |
880 | /// [`Operand::Copy`]. It then dereferences the resulting pointer, creating a place of the | |
881 | /// pointee's type. The resulting address is the address that was stored in the pointer. If the | |
882 | /// pointee type is unsized, the pointer additionally stored the value of the metadata. | |
883 | /// | |
884 | /// Computing a place may cause UB. One possibility is that the pointer used for a `Deref` may not | |
885 | /// be suitably aligned. Another possibility is that the place is not in bounds, meaning it does not | |
886 | /// point to an actual allocation. | |
887 | /// | |
888 | /// However, if this is actually UB and when the UB kicks in is undecided. This is being discussed | |
889 | /// in [UCG#319]. The options include that every place must obey those rules, that only some places | |
890 | /// must obey them, or that places impose no rules of their own. | |
891 | /// | |
892 | /// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319 | |
893 | /// | |
894 | /// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken | |
895 | /// advantage of by codegen (via `gep inbounds`). That is possibly subject to change. | |
f2b60f7d | 896 | #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable, TypeFoldable, TypeVisitable)] |
064997fb FG |
897 | pub struct Place<'tcx> { |
898 | pub local: Local, | |
899 | ||
900 | /// projection out of a place (access a field, deref a pointer, etc) | |
901 | pub projection: &'tcx List<PlaceElem<'tcx>>, | |
902 | } | |
903 | ||
904 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
f2b60f7d | 905 | #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] |
064997fb FG |
906 | pub enum ProjectionElem<V, T> { |
907 | Deref, | |
908 | Field(Field, T), | |
909 | /// Index into a slice/array. | |
910 | /// | |
911 | /// Note that this does not also dereference, and so it does not exactly correspond to slice | |
912 | /// indexing in Rust. In other words, in the below Rust code: | |
913 | /// | |
914 | /// ```rust | |
915 | /// let x = &[1, 2, 3, 4]; | |
916 | /// let i = 2; | |
917 | /// x[i]; | |
918 | /// ``` | |
919 | /// | |
920 | /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same | |
921 | /// thing is true of the `ConstantIndex` and `Subslice` projections below. | |
922 | Index(V), | |
923 | ||
924 | /// These indices are generated by slice patterns. Easiest to explain | |
925 | /// by example: | |
926 | /// | |
927 | /// ```ignore (illustrative) | |
928 | /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, | |
929 | /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, | |
930 | /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, | |
931 | /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, | |
932 | /// ``` | |
933 | ConstantIndex { | |
934 | /// index or -index (in Python terms), depending on from_end | |
935 | offset: u64, | |
936 | /// The thing being indexed must be at least this long. For arrays this | |
937 | /// is always the exact length. | |
938 | min_length: u64, | |
939 | /// Counting backwards from end? This is always false when indexing an | |
940 | /// array. | |
941 | from_end: bool, | |
942 | }, | |
943 | ||
944 | /// These indices are generated by slice patterns. | |
945 | /// | |
946 | /// If `from_end` is true `slice[from..slice.len() - to]`. | |
947 | /// Otherwise `array[from..to]`. | |
948 | Subslice { | |
949 | from: u64, | |
950 | to: u64, | |
951 | /// Whether `to` counts from the start or end of the array/slice. | |
952 | /// For `PlaceElem`s this is `true` if and only if the base is a slice. | |
953 | /// For `ProjectionKind`, this can also be `true` for arrays. | |
954 | from_end: bool, | |
955 | }, | |
956 | ||
957 | /// "Downcast" to a variant of an enum or a generator. | |
958 | /// | |
959 | /// The included Symbol is the name of the variant, used for printing MIR. | |
960 | Downcast(Option<Symbol>, VariantIdx), | |
2b03887a FG |
961 | |
962 | /// Like an explicit cast from an opaque type to a concrete type, but without | |
963 | /// requiring an intermediate variable. | |
964 | OpaqueCast(T), | |
064997fb FG |
965 | } |
966 | ||
967 | /// Alias for projections as they appear in places, where the base is a place | |
968 | /// and the index is a local. | |
969 | pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; | |
970 | ||
971 | /////////////////////////////////////////////////////////////////////////// | |
972 | // Operands | |
973 | ||
974 | /// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of | |
975 | /// the memory model. One proposal for a definition of values can be found [on UCG][value-def]. | |
976 | /// | |
977 | /// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md | |
978 | /// | |
979 | /// The most common way to create values is via loading a place. Loading a place is an operation | |
980 | /// which reads the memory of the place and converts it to a value. This is a fundamentally *typed* | |
981 | /// operation. The nature of the value produced depends on the type of the conversion. Furthermore, | |
982 | /// there may be other effects: if the type has a validity constraint loading the place might be UB | |
983 | /// if the validity constraint is not met. | |
984 | /// | |
985 | /// **Needs clarification:** Ralf proposes that loading a place not have side-effects. | |
986 | /// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this | |
987 | /// something we can even decide without knowing more about Rust's memory model? | |
988 | /// | |
989 | /// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri | |
990 | /// currently implements it, but it seems like this may be something to check against in the | |
991 | /// validator. | |
f2b60f7d | 992 | #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] |
064997fb FG |
993 | pub enum Operand<'tcx> { |
994 | /// Creates a value by loading the given place. | |
995 | /// | |
996 | /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there | |
997 | /// is no such requirement. | |
998 | Copy(Place<'tcx>), | |
999 | ||
1000 | /// Creates a value by performing loading the place, just like the `Copy` operand. | |
1001 | /// | |
1002 | /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide | |
1003 | /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this | |
1004 | /// place without first re-initializing it. | |
1005 | /// | |
1006 | /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188 | |
1007 | Move(Place<'tcx>), | |
1008 | ||
1009 | /// Constants are already semantically values, and remain unchanged. | |
1010 | Constant(Box<Constant<'tcx>>), | |
1011 | } | |
1012 | ||
1013 | /////////////////////////////////////////////////////////////////////////// | |
1014 | // Rvalues | |
1015 | ||
1016 | /// The various kinds of rvalues that can appear in MIR. | |
1017 | /// | |
1018 | /// Not all of these are allowed at every [`MirPhase`] - when this is the case, it's stated below. | |
1019 | /// | |
1020 | /// Computing any rvalue begins by evaluating the places and operands in some order (**Needs | |
1021 | /// clarification**: Which order?). These are then used to produce a "value" - the same kind of | |
1022 | /// value that an [`Operand`] produces. | |
f2b60f7d | 1023 | #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] |
064997fb FG |
1024 | pub enum Rvalue<'tcx> { |
1025 | /// Yields the operand unchanged | |
1026 | Use(Operand<'tcx>), | |
1027 | ||
1028 | /// Creates an array where each element is the value of the operand. | |
1029 | /// | |
1030 | /// This is the cause of a bug in the case where the repetition count is zero because the value | |
1031 | /// is not dropped, see [#74836]. | |
1032 | /// | |
1033 | /// Corresponds to source code like `[x; 32]`. | |
1034 | /// | |
1035 | /// [#74836]: https://github.com/rust-lang/rust/issues/74836 | |
1036 | Repeat(Operand<'tcx>, ty::Const<'tcx>), | |
1037 | ||
1038 | /// Creates a reference of the indicated kind to the place. | |
1039 | /// | |
1040 | /// There is not much to document here, because besides the obvious parts the semantics of this | |
1041 | /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing | |
1042 | /// exactly what the behavior of this operation should be. | |
1043 | /// | |
1044 | /// `Shallow` borrows are disallowed after drop lowering. | |
1045 | Ref(Region<'tcx>, BorrowKind, Place<'tcx>), | |
1046 | ||
1047 | /// Creates a pointer/reference to the given thread local. | |
1048 | /// | |
1049 | /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a | |
1050 | /// `*const T`, and if neither of those apply a `&T`. | |
1051 | /// | |
1052 | /// **Note:** This is a runtime operation that actually executes code and is in this sense more | |
1053 | /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to | |
1054 | /// SIGILL for some reason that I (JakobDegen) never got a chance to look into. | |
1055 | /// | |
1056 | /// **Needs clarification**: Are there weird additional semantics here related to the runtime | |
1057 | /// nature of this operation? | |
1058 | ThreadLocalRef(DefId), | |
1059 | ||
1060 | /// Creates a pointer with the indicated mutability to the place. | |
1061 | /// | |
1062 | /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like | |
1063 | /// `&raw v` or `addr_of!(v)`. | |
1064 | /// | |
1065 | /// Like with references, the semantics of this operation are heavily dependent on the aliasing | |
1066 | /// model. | |
1067 | AddressOf(Mutability, Place<'tcx>), | |
1068 | ||
1069 | /// Yields the length of the place, as a `usize`. | |
1070 | /// | |
1071 | /// If the type of the place is an array, this is the array length. For slices (`[T]`, not | |
1072 | /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is | |
1073 | /// ill-formed for places of other types. | |
1074 | Len(Place<'tcx>), | |
1075 | ||
1076 | /// Performs essentially all of the casts that can be performed via `as`. | |
1077 | /// | |
1078 | /// This allows for casts from/to a variety of types. | |
1079 | /// | |
1080 | /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why | |
1081 | /// `ArrayToPointer` and `MutToConstPointer` are special. | |
1082 | Cast(CastKind, Operand<'tcx>, Ty<'tcx>), | |
1083 | ||
1084 | /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second | |
1085 | /// parameter may be a `usize` as well. | |
1086 | /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, | |
1087 | /// raw pointers, or function pointers and return a `bool`. The types of the operands must be | |
1088 | /// matching, up to the usual caveat of the lifetimes in function pointers. | |
1089 | /// * Left and right shift operations accept signed or unsigned integers not necessarily of the | |
1090 | /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is | |
1091 | /// truncated as needed. | |
1092 | /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching | |
1093 | /// types and return a value of that type. | |
1094 | /// * The remaining operations accept signed integers, unsigned integers, or floats with | |
1095 | /// matching types and return a value of that type. | |
1096 | BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), | |
1097 | ||
1098 | /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. | |
1099 | /// | |
1100 | /// When overflow checking is disabled and we are generating run-time code, the error condition | |
1101 | /// is false. Otherwise, and always during CTFE, the error condition is determined as described | |
1102 | /// below. | |
1103 | /// | |
1104 | /// For addition, subtraction, and multiplication on integers the error condition is set when | |
1105 | /// the infinite precision result would be unequal to the actual result. | |
1106 | /// | |
1107 | /// For shift operations on integers the error condition is set when the value of right-hand | |
1108 | /// side is greater than or equal to the number of bits in the type of the left-hand side, or | |
1109 | /// when the value of right-hand side is negative. | |
1110 | /// | |
1111 | /// Other combinations of types and operators are unsupported. | |
1112 | CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), | |
1113 | ||
1114 | /// Computes a value as described by the operation. | |
1115 | NullaryOp(NullOp, Ty<'tcx>), | |
1116 | ||
1117 | /// Exactly like `BinaryOp`, but less operands. | |
1118 | /// | |
1119 | /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; | |
1120 | /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds | |
1121 | /// return a value with the same type as their operand. | |
1122 | UnaryOp(UnOp, Operand<'tcx>), | |
1123 | ||
1124 | /// Computes the discriminant of the place, returning it as an integer of type | |
1125 | /// [`discriminant_ty`]. Returns zero for types without discriminant. | |
1126 | /// | |
1127 | /// The validity requirements for the underlying value are undecided for this rvalue, see | |
1128 | /// [#91095]. Note too that the value of the discriminant is not the same thing as the | |
1129 | /// variant index; use [`discriminant_for_variant`] to convert. | |
1130 | /// | |
1131 | /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty | |
1132 | /// [#91095]: https://github.com/rust-lang/rust/issues/91095 | |
1133 | /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant | |
1134 | Discriminant(Place<'tcx>), | |
1135 | ||
1136 | /// Creates an aggregate value, like a tuple or struct. | |
1137 | /// | |
1138 | /// This is needed because dataflow analysis needs to distinguish | |
1139 | /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo` | |
1140 | /// has a destructor. | |
1141 | /// | |
1142 | /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After | |
1143 | /// generator lowering, `Generator` aggregate kinds are disallowed too. | |
1144 | Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), | |
1145 | ||
1146 | /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. | |
1147 | /// | |
1148 | /// This is different from a normal transmute because dataflow analysis will treat the box as | |
1149 | /// initialized but its content as uninitialized. Like other pointer casts, this in general | |
1150 | /// affects alias analysis. | |
1151 | ShallowInitBox(Operand<'tcx>, Ty<'tcx>), | |
1152 | ||
1153 | /// A CopyForDeref is equivalent to a read from a place at the | |
1154 | /// codegen level, but is treated specially by drop elaboration. When such a read happens, it | |
1155 | /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator) | |
1156 | /// that the only use of the returned value is a deref operation, immediately | |
1157 | /// followed by one or more projections. Drop elaboration treats this rvalue as if the | |
1158 | /// read never happened and just projects further. This allows simplifying various MIR | |
1159 | /// optimizations and codegen backends that previously had to handle deref operations anywhere | |
1160 | /// in a place. | |
1161 | CopyForDeref(Place<'tcx>), | |
1162 | } | |
1163 | ||
1164 | #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] | |
1165 | pub enum CastKind { | |
1166 | /// An exposing pointer to address cast. A cast between a pointer and an integer type, or | |
1167 | /// between a function pointer and an integer type. | |
1168 | /// See the docs on `expose_addr` for more details. | |
1169 | PointerExposeAddress, | |
1170 | /// An address-to-pointer cast that picks up an exposed provenance. | |
1171 | /// See the docs on `from_exposed_addr` for more details. | |
1172 | PointerFromExposedAddress, | |
1173 | /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are | |
1174 | /// translated into `&raw mut/const *r`, i.e., they are not actually casts. | |
1175 | Pointer(PointerCast), | |
f2b60f7d FG |
1176 | /// Cast into a dyn* object. |
1177 | DynStar, | |
2b03887a FG |
1178 | IntToInt, |
1179 | FloatToInt, | |
1180 | FloatToFloat, | |
1181 | IntToFloat, | |
1182 | PtrToPtr, | |
1183 | FnPtrToPtr, | |
064997fb FG |
1184 | } |
1185 | ||
1186 | #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] | |
f2b60f7d | 1187 | #[derive(TypeFoldable, TypeVisitable)] |
064997fb FG |
1188 | pub enum AggregateKind<'tcx> { |
1189 | /// The type is of the element | |
1190 | Array(Ty<'tcx>), | |
1191 | Tuple, | |
1192 | ||
1193 | /// The second field is the variant index. It's equal to 0 for struct | |
1194 | /// and union expressions. The fourth field is | |
1195 | /// active field number and is present only for union expressions | |
1196 | /// -- e.g., for a union expression `SomeUnion { c: .. }`, the | |
1197 | /// active field index would identity the field `c` | |
1198 | Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), | |
1199 | ||
1200 | // Note: We can use LocalDefId since closures and generators a deaggregated | |
1201 | // before codegen. | |
1202 | Closure(LocalDefId, SubstsRef<'tcx>), | |
1203 | Generator(LocalDefId, SubstsRef<'tcx>, hir::Movability), | |
1204 | } | |
1205 | ||
1206 | #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] | |
1207 | pub enum NullOp { | |
1208 | /// Returns the size of a value of that type | |
1209 | SizeOf, | |
1210 | /// Returns the minimum alignment of a type | |
1211 | AlignOf, | |
1212 | } | |
1213 | ||
487cf647 FG |
1214 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
1215 | #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] | |
064997fb FG |
1216 | pub enum UnOp { |
1217 | /// The `!` operator for logical inversion | |
1218 | Not, | |
1219 | /// The `-` operator for negation | |
1220 | Neg, | |
1221 | } | |
1222 | ||
487cf647 FG |
1223 | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] |
1224 | #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] | |
064997fb FG |
1225 | pub enum BinOp { |
1226 | /// The `+` operator (addition) | |
1227 | Add, | |
1228 | /// The `-` operator (subtraction) | |
1229 | Sub, | |
1230 | /// The `*` operator (multiplication) | |
1231 | Mul, | |
1232 | /// The `/` operator (division) | |
1233 | /// | |
1234 | /// Division by zero is UB, because the compiler should have inserted checks | |
1235 | /// prior to this. | |
1236 | Div, | |
1237 | /// The `%` operator (modulus) | |
1238 | /// | |
1239 | /// Using zero as the modulus (second operand) is UB, because the compiler | |
1240 | /// should have inserted checks prior to this. | |
1241 | Rem, | |
1242 | /// The `^` operator (bitwise xor) | |
1243 | BitXor, | |
1244 | /// The `&` operator (bitwise and) | |
1245 | BitAnd, | |
1246 | /// The `|` operator (bitwise or) | |
1247 | BitOr, | |
1248 | /// The `<<` operator (shift left) | |
1249 | /// | |
1250 | /// The offset is truncated to the size of the first operand before shifting. | |
1251 | Shl, | |
1252 | /// The `>>` operator (shift right) | |
1253 | /// | |
1254 | /// The offset is truncated to the size of the first operand before shifting. | |
1255 | Shr, | |
1256 | /// The `==` operator (equality) | |
1257 | Eq, | |
1258 | /// The `<` operator (less than) | |
1259 | Lt, | |
1260 | /// The `<=` operator (less than or equal to) | |
1261 | Le, | |
1262 | /// The `!=` operator (not equal to) | |
1263 | Ne, | |
1264 | /// The `>=` operator (greater than or equal to) | |
1265 | Ge, | |
1266 | /// The `>` operator (greater than) | |
1267 | Gt, | |
1268 | /// The `ptr.offset` operator | |
1269 | Offset, | |
1270 | } | |
1271 | ||
1272 | // Some nodes are used a lot. Make sure they don't unintentionally get bigger. | |
1273 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] | |
1274 | mod size_asserts { | |
1275 | use super::*; | |
2b03887a | 1276 | // tidy-alphabetical-start |
f2b60f7d | 1277 | static_assert_size!(AggregateKind<'_>, 40); |
064997fb FG |
1278 | static_assert_size!(Operand<'_>, 24); |
1279 | static_assert_size!(Place<'_>, 16); | |
1280 | static_assert_size!(PlaceElem<'_>, 24); | |
1281 | static_assert_size!(Rvalue<'_>, 40); | |
2b03887a | 1282 | // tidy-alphabetical-end |
064997fb | 1283 | } |