]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
0531ce1d | 11 | //! MIR datatypes and passes. See the [rustc guide] for more info. |
ff7c6d11 | 12 | //! |
0531ce1d | 13 | //! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html |
7cac9316 | 14 | |
7453a54e | 15 | use graphviz::IntoCow; |
c30ab7b3 | 16 | use hir::def::CtorKind; |
54a0048b | 17 | use hir::def_id::DefId; |
3b2f2976 | 18 | use hir::{self, InlineAsm}; |
94b46f34 XL |
19 | use middle::region; |
20 | use mir::interpret::{EvalErrorKind, Scalar, Value}; | |
21 | use mir::visit::MirVisitable; | |
22 | use rustc_apfloat::ieee::{Double, Single}; | |
23 | use rustc_apfloat::Float; | |
24 | use rustc_data_structures::control_flow_graph::dominators::{dominators, Dominators}; | |
25 | use rustc_data_structures::control_flow_graph::ControlFlowGraph; | |
26 | use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors}; | |
27 | use rustc_data_structures::indexed_vec::{Idx, IndexVec}; | |
28 | use rustc_data_structures::small_vec::SmallVec; | |
29 | use rustc_data_structures::sync::Lrc; | |
83c7162d | 30 | use rustc_data_structures::sync::ReadGuard; |
94b46f34 XL |
31 | use rustc_serialize as serialize; |
32 | use std::borrow::Cow; | |
9cc50fc6 | 33 | use std::fmt::{self, Debug, Formatter, Write}; |
9cc50fc6 | 34 | use std::ops::{Index, IndexMut}; |
94b46f34 | 35 | use std::slice; |
3157f602 | 36 | use std::vec::IntoIter; |
94b46f34 | 37 | use std::{iter, mem, option, u32}; |
ea8adc8c | 38 | use syntax::ast::{self, Name}; |
ff7c6d11 | 39 | use syntax::symbol::InternedString; |
0531ce1d | 40 | use syntax_pos::{Span, DUMMY_SP}; |
94b46f34 XL |
41 | use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; |
42 | use ty::subst::{Subst, Substs}; | |
43 | use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt}; | |
44 | use util::ppaux; | |
83c7162d XL |
45 | |
46 | pub use mir::interpret::AssertMessage; | |
3157f602 | 47 | |
c30ab7b3 | 48 | mod cache; |
ff7c6d11 XL |
49 | pub mod interpret; |
50 | pub mod mono; | |
94b46f34 XL |
51 | pub mod tcx; |
52 | pub mod traversal; | |
53 | pub mod visit; | |
3157f602 | 54 | |
041b39d2 XL |
55 | /// Types for locals |
56 | type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>; | |
57 | ||
58 | pub trait HasLocalDecls<'tcx> { | |
59 | fn local_decls(&self) -> &LocalDecls<'tcx>; | |
60 | } | |
61 | ||
62 | impl<'tcx> HasLocalDecls<'tcx> for LocalDecls<'tcx> { | |
63 | fn local_decls(&self) -> &LocalDecls<'tcx> { | |
64 | self | |
65 | } | |
66 | } | |
67 | ||
68 | impl<'tcx> HasLocalDecls<'tcx> for Mir<'tcx> { | |
69 | fn local_decls(&self) -> &LocalDecls<'tcx> { | |
70 | &self.local_decls | |
71 | } | |
72 | } | |
73 | ||
e9174d1e | 74 | /// Lowered representation of a single function. |
8bb4bdeb | 75 | #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] |
b039eaaf | 76 | pub struct Mir<'tcx> { |
92a42be0 SL |
77 | /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` |
78 | /// that indexes into this vector. | |
3157f602 | 79 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, |
e9174d1e | 80 | |
94b46f34 XL |
81 | /// List of source scopes; these are referenced by statements |
82 | /// and used for debuginfo. Indexed by a `SourceScope`. | |
83 | pub source_scopes: IndexVec<SourceScope, SourceScopeData>, | |
54a0048b | 84 | |
94b46f34 | 85 | /// Crate-local information for each source scope, that can't (and |
ea8adc8c | 86 | /// needn't) be tracked across crates. |
94b46f34 | 87 | pub source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>, |
ea8adc8c | 88 | |
a7813a04 XL |
89 | /// Rvalues promoted from this function, such as borrows of constants. |
90 | /// Each of them is the Mir of a constant with the fn's type parameters | |
c30ab7b3 | 91 | /// in scope, but a separate set of locals. |
3157f602 | 92 | pub promoted: IndexVec<Promoted, Mir<'tcx>>, |
a7813a04 | 93 | |
ea8adc8c XL |
94 | /// Yield type of the function, if it is a generator. |
95 | pub yield_ty: Option<Ty<'tcx>>, | |
96 | ||
97 | /// Generator drop glue | |
98 | pub generator_drop: Option<Box<Mir<'tcx>>>, | |
99 | ||
100 | /// The layout of a generator. Produced by the state transformation. | |
101 | pub generator_layout: Option<GeneratorLayout<'tcx>>, | |
102 | ||
c30ab7b3 SL |
103 | /// Declarations of locals. |
104 | /// | |
105 | /// The first local is the return value pointer, followed by `arg_count` | |
106 | /// locals for the function arguments, followed by any user-declared | |
107 | /// variables and temporaries. | |
041b39d2 | 108 | pub local_decls: LocalDecls<'tcx>, |
92a42be0 | 109 | |
c30ab7b3 SL |
110 | /// Number of arguments this function takes. |
111 | /// | |
112 | /// Starting at local 1, `arg_count` locals will be provided by the caller | |
113 | /// and can be assumed to be initialized. | |
114 | /// | |
115 | /// If this MIR was built for a constant, this will be 0. | |
116 | pub arg_count: usize, | |
7453a54e | 117 | |
a7813a04 XL |
118 | /// Names and capture modes of all the closure upvars, assuming |
119 | /// the first argument is either the closure or a reference to it. | |
120 | pub upvar_decls: Vec<UpvarDecl>, | |
121 | ||
c30ab7b3 SL |
122 | /// Mark an argument local (which must be a tuple) as getting passed as |
123 | /// its individual components at the LLVM level. | |
124 | /// | |
125 | /// This is used for the "rust-call" ABI. | |
126 | pub spread_arg: Option<Local>, | |
127 | ||
7453a54e SL |
128 | /// A span representing this MIR, for error reporting |
129 | pub span: Span, | |
3157f602 XL |
130 | |
131 | /// A cache for various calculations | |
94b46f34 | 132 | cache: cache::Cache, |
e9174d1e SL |
133 | } |
134 | ||
135 | /// where execution begins | |
136 | pub const START_BLOCK: BasicBlock = BasicBlock(0); | |
137 | ||
b039eaaf | 138 | impl<'tcx> Mir<'tcx> { |
94b46f34 XL |
139 | pub fn new( |
140 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, | |
141 | source_scopes: IndexVec<SourceScope, SourceScopeData>, | |
142 | source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>, | |
143 | promoted: IndexVec<Promoted, Mir<'tcx>>, | |
144 | yield_ty: Option<Ty<'tcx>>, | |
145 | local_decls: IndexVec<Local, LocalDecl<'tcx>>, | |
146 | arg_count: usize, | |
147 | upvar_decls: Vec<UpvarDecl>, | |
148 | span: Span, | |
149 | ) -> Self { | |
ff7c6d11 | 150 | // We need `arg_count` locals, and one for the return place |
94b46f34 XL |
151 | assert!( |
152 | local_decls.len() >= arg_count + 1, | |
153 | "expected at least {} locals, got {}", | |
154 | arg_count + 1, | |
155 | local_decls.len() | |
156 | ); | |
c30ab7b3 | 157 | |
3157f602 | 158 | Mir { |
041b39d2 | 159 | basic_blocks, |
94b46f34 XL |
160 | source_scopes, |
161 | source_scope_local_data, | |
041b39d2 | 162 | promoted, |
ea8adc8c XL |
163 | yield_ty, |
164 | generator_drop: None, | |
165 | generator_layout: None, | |
041b39d2 XL |
166 | local_decls, |
167 | arg_count, | |
168 | upvar_decls, | |
c30ab7b3 | 169 | spread_arg: None, |
041b39d2 | 170 | span, |
94b46f34 | 171 | cache: cache::Cache::new(), |
3157f602 XL |
172 | } |
173 | } | |
174 | ||
175 | #[inline] | |
176 | pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> { | |
177 | &self.basic_blocks | |
178 | } | |
179 | ||
180 | #[inline] | |
181 | pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { | |
182 | self.cache.invalidate(); | |
183 | &mut self.basic_blocks | |
e9174d1e SL |
184 | } |
185 | ||
ff7c6d11 | 186 | #[inline] |
94b46f34 XL |
187 | pub fn basic_blocks_and_local_decls_mut( |
188 | &mut self, | |
189 | ) -> ( | |
ff7c6d11 XL |
190 | &mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, |
191 | &mut LocalDecls<'tcx>, | |
192 | ) { | |
193 | self.cache.invalidate(); | |
194 | (&mut self.basic_blocks, &mut self.local_decls) | |
195 | } | |
196 | ||
3157f602 | 197 | #[inline] |
83c7162d | 198 | pub fn predecessors(&self) -> ReadGuard<IndexVec<BasicBlock, Vec<BasicBlock>>> { |
3157f602 | 199 | self.cache.predecessors(self) |
e9174d1e SL |
200 | } |
201 | ||
3157f602 | 202 | #[inline] |
83c7162d XL |
203 | pub fn predecessors_for(&self, bb: BasicBlock) -> ReadGuard<Vec<BasicBlock>> { |
204 | ReadGuard::map(self.predecessors(), |p| &p[bb]) | |
3157f602 XL |
205 | } |
206 | ||
207 | #[inline] | |
208 | pub fn dominators(&self) -> Dominators<BasicBlock> { | |
209 | dominators(self) | |
210 | } | |
211 | ||
c30ab7b3 SL |
212 | #[inline] |
213 | pub fn local_kind(&self, local: Local) -> LocalKind { | |
214 | let index = local.0 as usize; | |
215 | if index == 0 { | |
94b46f34 XL |
216 | debug_assert!( |
217 | self.local_decls[local].mutability == Mutability::Mut, | |
218 | "return place should be mutable" | |
219 | ); | |
c30ab7b3 SL |
220 | |
221 | LocalKind::ReturnPointer | |
222 | } else if index < self.arg_count + 1 { | |
223 | LocalKind::Arg | |
224 | } else if self.local_decls[local].name.is_some() { | |
225 | LocalKind::Var | |
226 | } else { | |
94b46f34 XL |
227 | debug_assert!( |
228 | self.local_decls[local].mutability == Mutability::Mut, | |
229 | "temp should be mutable" | |
230 | ); | |
c30ab7b3 SL |
231 | |
232 | LocalKind::Temp | |
233 | } | |
234 | } | |
235 | ||
236 | /// Returns an iterator over all temporaries. | |
237 | #[inline] | |
94b46f34 XL |
238 | pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { |
239 | (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { | |
c30ab7b3 | 240 | let local = Local::new(index); |
94b46f34 | 241 | if self.local_decls[local].is_user_variable.is_some() { |
c30ab7b3 | 242 | None |
cc61c64b XL |
243 | } else { |
244 | Some(local) | |
3157f602 | 245 | } |
c30ab7b3 SL |
246 | }) |
247 | } | |
248 | ||
249 | /// Returns an iterator over all user-declared locals. | |
250 | #[inline] | |
94b46f34 XL |
251 | pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { |
252 | (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { | |
c30ab7b3 | 253 | let local = Local::new(index); |
94b46f34 | 254 | if self.local_decls[local].is_user_variable.is_some() { |
c30ab7b3 | 255 | Some(local) |
cc61c64b XL |
256 | } else { |
257 | None | |
3157f602 | 258 | } |
c30ab7b3 | 259 | }) |
3157f602 XL |
260 | } |
261 | ||
83c7162d XL |
262 | /// Returns an iterator over all user-declared mutable arguments and locals. |
263 | #[inline] | |
94b46f34 | 264 | pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { |
83c7162d XL |
265 | (1..self.local_decls.len()).filter_map(move |index| { |
266 | let local = Local::new(index); | |
267 | let decl = &self.local_decls[local]; | |
94b46f34 XL |
268 | if (decl.is_user_variable.is_some() || index < self.arg_count + 1) |
269 | && decl.mutability == Mutability::Mut | |
83c7162d XL |
270 | { |
271 | Some(local) | |
272 | } else { | |
273 | None | |
274 | } | |
275 | }) | |
276 | } | |
277 | ||
c30ab7b3 SL |
278 | /// Returns an iterator over all function arguments. |
279 | #[inline] | |
94b46f34 | 280 | pub fn args_iter(&self) -> impl Iterator<Item = Local> { |
c30ab7b3 | 281 | let arg_count = self.arg_count; |
94b46f34 | 282 | (1..arg_count + 1).map(Local::new) |
e9174d1e | 283 | } |
9e0c209e | 284 | |
c30ab7b3 | 285 | /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all |
ff7c6d11 | 286 | /// locals that are neither arguments nor the return place). |
c30ab7b3 | 287 | #[inline] |
94b46f34 | 288 | pub fn vars_and_temps_iter(&self) -> impl Iterator<Item = Local> { |
c30ab7b3 SL |
289 | let arg_count = self.arg_count; |
290 | let local_count = self.local_decls.len(); | |
94b46f34 | 291 | (arg_count + 1..local_count).map(Local::new) |
9e0c209e SL |
292 | } |
293 | ||
294 | /// Changes a statement to a nop. This is both faster than deleting instructions and avoids | |
295 | /// invalidating statement indices in `Location`s. | |
296 | pub fn make_statement_nop(&mut self, location: Location) { | |
297 | let block = &mut self[location.block]; | |
298 | debug_assert!(location.statement_index < block.statements.len()); | |
299 | block.statements[location.statement_index].make_nop() | |
300 | } | |
ea8adc8c XL |
301 | |
302 | /// Returns the source info associated with `location`. | |
303 | pub fn source_info(&self, location: Location) -> &SourceInfo { | |
304 | let block = &self[location.block]; | |
305 | let stmts = &block.statements; | |
306 | let idx = location.statement_index; | |
abe05a73 | 307 | if idx < stmts.len() { |
ea8adc8c XL |
308 | &stmts[idx].source_info |
309 | } else { | |
abe05a73 | 310 | assert!(idx == stmts.len()); |
ea8adc8c XL |
311 | &block.terminator().source_info |
312 | } | |
313 | } | |
abe05a73 | 314 | |
94b46f34 XL |
315 | /// Check if `sub` is a sub scope of `sup` |
316 | pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool { | |
317 | loop { | |
318 | if sub == sup { | |
319 | return true; | |
320 | } | |
321 | match self.source_scopes[sub].parent_scope { | |
322 | None => return false, | |
323 | Some(p) => sub = p, | |
324 | } | |
325 | } | |
326 | } | |
327 | ||
abe05a73 XL |
328 | /// Return the return type, it always return first element from `local_decls` array |
329 | pub fn return_ty(&self) -> Ty<'tcx> { | |
ff7c6d11 | 330 | self.local_decls[RETURN_PLACE].ty |
abe05a73 | 331 | } |
ea8adc8c XL |
332 | } |
333 | ||
ff7c6d11 | 334 | #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] |
ea8adc8c XL |
335 | pub enum Safety { |
336 | Safe, | |
337 | /// Unsafe because of a PushUnsafeBlock | |
338 | BuiltinUnsafe, | |
339 | /// Unsafe because of an unsafe fn | |
340 | FnUnsafe, | |
341 | /// Unsafe because of an `unsafe` block | |
94b46f34 | 342 | ExplicitUnsafe(ast::NodeId), |
e9174d1e SL |
343 | } |
344 | ||
cc61c64b XL |
345 | impl_stable_hash_for!(struct Mir<'tcx> { |
346 | basic_blocks, | |
94b46f34 XL |
347 | source_scopes, |
348 | source_scope_local_data, | |
cc61c64b | 349 | promoted, |
ea8adc8c XL |
350 | yield_ty, |
351 | generator_drop, | |
352 | generator_layout, | |
cc61c64b XL |
353 | local_decls, |
354 | arg_count, | |
355 | upvar_decls, | |
356 | spread_arg, | |
357 | span, | |
358 | cache | |
359 | }); | |
360 | ||
9cc50fc6 SL |
361 | impl<'tcx> Index<BasicBlock> for Mir<'tcx> { |
362 | type Output = BasicBlockData<'tcx>; | |
363 | ||
364 | #[inline] | |
365 | fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { | |
3157f602 | 366 | &self.basic_blocks()[index] |
9cc50fc6 SL |
367 | } |
368 | } | |
369 | ||
370 | impl<'tcx> IndexMut<BasicBlock> for Mir<'tcx> { | |
371 | #[inline] | |
372 | fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { | |
3157f602 | 373 | &mut self.basic_blocks_mut()[index] |
9cc50fc6 SL |
374 | } |
375 | } | |
376 | ||
94b46f34 | 377 | #[derive(Copy, Clone, Debug)] |
ff7c6d11 | 378 | pub enum ClearCrossCrate<T> { |
ea8adc8c | 379 | Clear, |
94b46f34 | 380 | Set(T), |
ea8adc8c XL |
381 | } |
382 | ||
ff7c6d11 XL |
383 | impl<T: serialize::Encodable> serialize::UseSpecializedEncodable for ClearCrossCrate<T> {} |
384 | impl<T: serialize::Decodable> serialize::UseSpecializedDecodable for ClearCrossCrate<T> {} | |
ea8adc8c | 385 | |
3157f602 XL |
386 | /// Grouped information about the source code origin of a MIR entity. |
387 | /// Intended to be inspected by diagnostics and debuginfo. | |
388 | /// Most passes can work with it as a whole, within a single function. | |
ea8adc8c | 389 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] |
3157f602 XL |
390 | pub struct SourceInfo { |
391 | /// Source span for the AST pertaining to this MIR entity. | |
392 | pub span: Span, | |
393 | ||
94b46f34 XL |
394 | /// The source scope, keeping track of which bindings can be |
395 | /// seen by debuginfo, active lint levels, `unsafe {...}`, etc. | |
396 | pub scope: SourceScope, | |
3157f602 XL |
397 | } |
398 | ||
e9174d1e SL |
399 | /////////////////////////////////////////////////////////////////////////// |
400 | // Mutability and borrow kinds | |
401 | ||
9cc50fc6 | 402 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
403 | pub enum Mutability { |
404 | Mut, | |
405 | Not, | |
406 | } | |
407 | ||
94b46f34 XL |
408 | impl From<Mutability> for hir::Mutability { |
409 | fn from(m: Mutability) -> Self { | |
410 | match m { | |
411 | Mutability::Mut => hir::MutMutable, | |
412 | Mutability::Not => hir::MutImmutable, | |
413 | } | |
414 | } | |
415 | } | |
416 | ||
9cc50fc6 | 417 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
418 | pub enum BorrowKind { |
419 | /// Data must be immutable and is aliasable. | |
420 | Shared, | |
421 | ||
422 | /// Data must be immutable but not aliasable. This kind of borrow | |
423 | /// cannot currently be expressed by the user and is used only in | |
424 | /// implicit closure bindings. It is needed when you the closure | |
425 | /// is borrowing or mutating a mutable referent, e.g.: | |
426 | /// | |
427 | /// let x: &mut isize = ...; | |
428 | /// let y = || *x += 5; | |
429 | /// | |
430 | /// If we were to try to translate this closure into a more explicit | |
431 | /// form, we'd encounter an error with the code as written: | |
432 | /// | |
433 | /// struct Env { x: & &mut isize } | |
434 | /// let x: &mut isize = ...; | |
435 | /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn | |
436 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
437 | /// | |
438 | /// This is then illegal because you cannot mutate a `&mut` found | |
439 | /// in an aliasable location. To solve, you'd have to translate with | |
440 | /// an `&mut` borrow: | |
441 | /// | |
442 | /// struct Env { x: & &mut isize } | |
443 | /// let x: &mut isize = ...; | |
444 | /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x | |
445 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
446 | /// | |
447 | /// Now the assignment to `**env.x` is legal, but creating a | |
448 | /// mutable pointer to `x` is not because `x` is not mutable. We | |
449 | /// could fix this by declaring `x` as `let mut x`. This is ok in | |
450 | /// user code, if awkward, but extra weird for closures, since the | |
451 | /// borrow is hidden. | |
452 | /// | |
453 | /// So we introduce a "unique imm" borrow -- the referent is | |
454 | /// immutable, but not aliasable. This solves the problem. For | |
455 | /// simplicity, we don't give users the way to express this | |
456 | /// borrow, it's just used when translating closures. | |
457 | Unique, | |
458 | ||
459 | /// Data is mutable and not aliasable. | |
2c00a5a8 XL |
460 | Mut { |
461 | /// True if this borrow arose from method-call auto-ref | |
462 | /// (i.e. `adjustment::Adjust::Borrow`) | |
94b46f34 XL |
463 | allow_two_phase_borrow: bool, |
464 | }, | |
2c00a5a8 XL |
465 | } |
466 | ||
467 | impl BorrowKind { | |
468 | pub fn allows_two_phase_borrow(&self) -> bool { | |
469 | match *self { | |
470 | BorrowKind::Shared | BorrowKind::Unique => false, | |
94b46f34 XL |
471 | BorrowKind::Mut { |
472 | allow_two_phase_borrow, | |
473 | } => allow_two_phase_borrow, | |
2c00a5a8 XL |
474 | } |
475 | } | |
e9174d1e SL |
476 | } |
477 | ||
478 | /////////////////////////////////////////////////////////////////////////// | |
479 | // Variables and temps | |
480 | ||
abe05a73 XL |
481 | newtype_index!(Local |
482 | { | |
483 | DEBUG_FORMAT = "_{}", | |
ff7c6d11 | 484 | const RETURN_PLACE = 0, |
abe05a73 | 485 | }); |
54a0048b | 486 | |
c30ab7b3 SL |
487 | /// Classifies locals into categories. See `Mir::local_kind`. |
488 | #[derive(PartialEq, Eq, Debug)] | |
489 | pub enum LocalKind { | |
490 | /// User-declared variable binding | |
491 | Var, | |
492 | /// Compiler-introduced temporary | |
493 | Temp, | |
494 | /// Function argument | |
495 | Arg, | |
496 | /// Location of function's return value | |
497 | ReturnPointer, | |
e9174d1e SL |
498 | } |
499 | ||
94b46f34 XL |
500 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] |
501 | pub struct VarBindingForm { | |
502 | /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? | |
503 | pub binding_mode: ty::BindingMode, | |
504 | /// If an explicit type was provided for this variable binding, | |
505 | /// this holds the source Span of that type. | |
506 | /// | |
507 | /// NOTE: If you want to change this to a `HirId`, be wary that | |
508 | /// doing so breaks incremental compilation (as of this writing), | |
509 | /// while a `Span` does not cause our tests to fail. | |
510 | pub opt_ty_info: Option<Span>, | |
511 | } | |
512 | ||
513 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] | |
514 | pub enum BindingForm { | |
515 | /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. | |
516 | Var(VarBindingForm), | |
517 | /// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit. | |
518 | ImplicitSelf, | |
519 | } | |
520 | ||
521 | CloneTypeFoldableAndLiftImpls! { BindingForm, } | |
522 | ||
523 | impl_stable_hash_for!(struct self::VarBindingForm { binding_mode, opt_ty_info }); | |
524 | ||
525 | impl_stable_hash_for!(enum self::BindingForm { Var(binding), ImplicitSelf, }); | |
526 | ||
c30ab7b3 | 527 | /// A MIR local. |
7453a54e | 528 | /// |
c30ab7b3 | 529 | /// This can be a binding declared by the user, a temporary inserted by the compiler, a function |
ff7c6d11 | 530 | /// argument, or the return place. |
7453a54e | 531 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
c30ab7b3 SL |
532 | pub struct LocalDecl<'tcx> { |
533 | /// `let mut x` vs `let x`. | |
534 | /// | |
ff7c6d11 | 535 | /// Temporaries and the return place are always mutable. |
c30ab7b3 SL |
536 | pub mutability: Mutability, |
537 | ||
94b46f34 XL |
538 | /// Some(binding_mode) if this corresponds to a user-declared local variable. |
539 | /// | |
540 | /// This is solely used for local diagnostics when generating | |
541 | /// warnings/errors when compiling the current crate, and | |
542 | /// therefore it need not be visible across crates. pnkfelix | |
543 | /// currently hypothesized we *need* to wrap this in a | |
544 | /// `ClearCrossCrate` as long as it carries as `HirId`. | |
545 | pub is_user_variable: Option<ClearCrossCrate<BindingForm>>, | |
cc61c64b | 546 | |
ea8adc8c XL |
547 | /// True if this is an internal local |
548 | /// | |
549 | /// These locals are not based on types in the source code and are only used | |
550 | /// for a few desugarings at the moment. | |
551 | /// | |
552 | /// The generator transformation will sanity check the locals which are live | |
553 | /// across a suspension point against the type components of the generator | |
554 | /// which type checking knows are live across a suspension point. We need to | |
555 | /// flag drop flags to avoid triggering this check as they are introduced | |
556 | /// after typeck. | |
557 | /// | |
558 | /// Unsafety checking will also ignore dereferences of these locals, | |
559 | /// so they can be used for raw pointers only used in a desugaring. | |
560 | /// | |
561 | /// This should be sound because the drop flags are fully algebraic, and | |
562 | /// therefore don't affect the OIBIT or outlives properties of the | |
563 | /// generator. | |
564 | pub internal: bool, | |
565 | ||
c30ab7b3 | 566 | /// Type of this local. |
b039eaaf | 567 | pub ty: Ty<'tcx>, |
54a0048b | 568 | |
c30ab7b3 SL |
569 | /// Name of the local, used in debuginfo and pretty-printing. |
570 | /// | |
571 | /// Note that function arguments can also have this set to `Some(_)` | |
572 | /// to generate better debuginfo. | |
573 | pub name: Option<Name>, | |
a7813a04 | 574 | |
94b46f34 | 575 | /// The *syntactic* (i.e. not visibility) source scope the local is defined |
ea8adc8c XL |
576 | /// in. If the local was defined in a let-statement, this |
577 | /// is *within* the let-statement, rather than outside | |
578 | /// of it. | |
ff7c6d11 | 579 | /// |
94b46f34 XL |
580 | /// This is needed because the visibility source scope of locals within |
581 | /// a let-statement is weird. | |
ff7c6d11 XL |
582 | /// |
583 | /// The reason is that we want the local to be *within* the let-statement | |
584 | /// for lint purposes, but we want the local to be *after* the let-statement | |
585 | /// for names-in-scope purposes. | |
586 | /// | |
587 | /// That's it, if we have a let-statement like the one in this | |
588 | /// function: | |
589 | /// | |
590 | /// ``` | |
591 | /// fn foo(x: &str) { | |
592 | /// #[allow(unused_mut)] | |
593 | /// let mut x: u32 = { // <- one unused mut | |
594 | /// let mut y: u32 = x.parse().unwrap(); | |
595 | /// y + 2 | |
596 | /// }; | |
597 | /// drop(x); | |
598 | /// } | |
599 | /// ``` | |
600 | /// | |
601 | /// Then, from a lint point of view, the declaration of `x: u32` | |
602 | /// (and `y: u32`) are within the `#[allow(unused_mut)]` scope - the | |
603 | /// lint scopes are the same as the AST/HIR nesting. | |
604 | /// | |
605 | /// However, from a name lookup point of view, the scopes look more like | |
606 | /// as if the let-statements were `match` expressions: | |
607 | /// | |
608 | /// ``` | |
609 | /// fn foo(x: &str) { | |
610 | /// match { | |
611 | /// match x.parse().unwrap() { | |
612 | /// y => y + 2 | |
613 | /// } | |
614 | /// } { | |
615 | /// x => drop(x) | |
616 | /// }; | |
617 | /// } | |
618 | /// ``` | |
619 | /// | |
620 | /// We care about the name-lookup scopes for debuginfo - if the | |
621 | /// debuginfo instruction pointer is at the call to `x.parse()`, we | |
622 | /// want `x` to refer to `x: &str`, but if it is at the call to | |
623 | /// `drop(x)`, we want it to refer to `x: u32`. | |
624 | /// | |
625 | /// To allow both uses to work, we need to have more than a single scope | |
94b46f34 | 626 | /// for a local. We have the `source_info.scope` represent the |
ff7c6d11 | 627 | /// "syntactic" lint scope (with a variable being under its let |
94b46f34 | 628 | /// block) while the `visibility_scope` represents the "local variable" |
ff7c6d11 XL |
629 | /// scope (where the "rest" of a block is under all prior let-statements). |
630 | /// | |
631 | /// The end result looks like this: | |
632 | /// | |
633 | /// ```text | |
634 | /// ROOT SCOPE | |
635 | /// │{ argument x: &str } | |
636 | /// │ | |
637 | /// │ │{ #[allow(unused_mut] } // this is actually split into 2 scopes | |
638 | /// │ │ // in practice because I'm lazy. | |
639 | /// │ │ | |
94b46f34 | 640 | /// │ │← x.source_info.scope |
ff7c6d11 XL |
641 | /// │ │← `x.parse().unwrap()` |
642 | /// │ │ | |
94b46f34 | 643 | /// │ │ │← y.source_info.scope |
ff7c6d11 XL |
644 | /// │ │ |
645 | /// │ │ │{ let y: u32 } | |
646 | /// │ │ │ | |
94b46f34 | 647 | /// │ │ │← y.visibility_scope |
ff7c6d11 XL |
648 | /// │ │ │← `y + 2` |
649 | /// │ | |
650 | /// │ │{ let x: u32 } | |
94b46f34 | 651 | /// │ │← x.visibility_scope |
ff7c6d11 XL |
652 | /// │ │← `drop(x)` // this accesses `x: u32` |
653 | /// ``` | |
94b46f34 XL |
654 | pub source_info: SourceInfo, |
655 | ||
656 | /// Source scope within which the local is visible (for debuginfo) | |
657 | /// (see `source_info` for more details). | |
658 | pub visibility_scope: SourceScope, | |
c30ab7b3 SL |
659 | } |
660 | ||
661 | impl<'tcx> LocalDecl<'tcx> { | |
94b46f34 XL |
662 | /// Returns true only if local is a binding that can itself be |
663 | /// made mutable via the addition of the `mut` keyword, namely | |
664 | /// something like the occurrences of `x` in: | |
665 | /// - `fn foo(x: Type) { ... }`, | |
666 | /// - `let x = ...`, | |
667 | /// - or `match ... { C(x) => ... }` | |
668 | pub fn can_be_made_mutable(&self) -> bool { | |
669 | match self.is_user_variable { | |
670 | Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { | |
671 | binding_mode: ty::BindingMode::BindByValue(_), | |
672 | opt_ty_info: _, | |
673 | }))) => true, | |
674 | ||
675 | // FIXME: might be able to thread the distinction between | |
676 | // `self`/`mut self`/`&self`/`&mut self` into the | |
677 | // `BindingForm::ImplicitSelf` variant, (and then return | |
678 | // true here for solely the first case). | |
679 | _ => false, | |
680 | } | |
681 | } | |
682 | ||
683 | /// Returns true if local is definitely not a `ref ident` or | |
684 | /// `ref mut ident` binding. (Such bindings cannot be made into | |
685 | /// mutable bindings, but the inverse does not necessarily hold). | |
686 | pub fn is_nonref_binding(&self) -> bool { | |
687 | match self.is_user_variable { | |
688 | Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { | |
689 | binding_mode: ty::BindingMode::BindByValue(_), | |
690 | opt_ty_info: _, | |
691 | }))) => true, | |
692 | ||
693 | Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true, | |
694 | ||
695 | _ => false, | |
696 | } | |
697 | } | |
698 | ||
c30ab7b3 SL |
699 | /// Create a new `LocalDecl` for a temporary. |
700 | #[inline] | |
cc61c64b | 701 | pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self { |
c30ab7b3 SL |
702 | LocalDecl { |
703 | mutability: Mutability::Mut, | |
041b39d2 | 704 | ty, |
c30ab7b3 | 705 | name: None, |
cc61c64b | 706 | source_info: SourceInfo { |
041b39d2 | 707 | span, |
94b46f34 | 708 | scope: OUTERMOST_SOURCE_SCOPE, |
cc61c64b | 709 | }, |
94b46f34 | 710 | visibility_scope: OUTERMOST_SOURCE_SCOPE, |
ea8adc8c | 711 | internal: false, |
94b46f34 | 712 | is_user_variable: None, |
ea8adc8c XL |
713 | } |
714 | } | |
715 | ||
716 | /// Create a new `LocalDecl` for a internal temporary. | |
717 | #[inline] | |
718 | pub fn new_internal(ty: Ty<'tcx>, span: Span) -> Self { | |
719 | LocalDecl { | |
720 | mutability: Mutability::Mut, | |
721 | ty, | |
722 | name: None, | |
723 | source_info: SourceInfo { | |
724 | span, | |
94b46f34 | 725 | scope: OUTERMOST_SOURCE_SCOPE, |
ea8adc8c | 726 | }, |
94b46f34 | 727 | visibility_scope: OUTERMOST_SOURCE_SCOPE, |
ea8adc8c | 728 | internal: true, |
94b46f34 | 729 | is_user_variable: None, |
c30ab7b3 SL |
730 | } |
731 | } | |
732 | ||
ff7c6d11 | 733 | /// Builds a `LocalDecl` for the return place. |
c30ab7b3 SL |
734 | /// |
735 | /// This must be inserted into the `local_decls` list as the first local. | |
736 | #[inline] | |
ff7c6d11 | 737 | pub fn new_return_place(return_ty: Ty, span: Span) -> LocalDecl { |
c30ab7b3 SL |
738 | LocalDecl { |
739 | mutability: Mutability::Mut, | |
740 | ty: return_ty, | |
cc61c64b | 741 | source_info: SourceInfo { |
041b39d2 | 742 | span, |
94b46f34 | 743 | scope: OUTERMOST_SOURCE_SCOPE, |
cc61c64b | 744 | }, |
94b46f34 | 745 | visibility_scope: OUTERMOST_SOURCE_SCOPE, |
ea8adc8c | 746 | internal: false, |
94b46f34 XL |
747 | name: None, // FIXME maybe we do want some name here? |
748 | is_user_variable: None, | |
c30ab7b3 SL |
749 | } |
750 | } | |
a7813a04 XL |
751 | } |
752 | ||
753 | /// A closure capture, with its name and mode. | |
754 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
755 | pub struct UpvarDecl { | |
756 | pub debug_name: Name, | |
757 | ||
758 | /// If true, the capture is behind a reference. | |
ff7c6d11 XL |
759 | pub by_ref: bool, |
760 | ||
761 | pub mutability: Mutability, | |
e9174d1e SL |
762 | } |
763 | ||
e9174d1e SL |
764 | /////////////////////////////////////////////////////////////////////////// |
765 | // BasicBlock | |
766 | ||
abe05a73 XL |
767 | newtype_index!(BasicBlock { DEBUG_FORMAT = "bb{}" }); |
768 | ||
769 | impl BasicBlock { | |
770 | pub fn start_location(self) -> Location { | |
771 | Location { | |
772 | block: self, | |
773 | statement_index: 0, | |
774 | } | |
775 | } | |
776 | } | |
e9174d1e SL |
777 | |
778 | /////////////////////////////////////////////////////////////////////////// | |
54a0048b | 779 | // BasicBlockData and Terminator |
e9174d1e | 780 | |
7453a54e | 781 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
b039eaaf | 782 | pub struct BasicBlockData<'tcx> { |
54a0048b | 783 | /// List of statements in this block. |
b039eaaf | 784 | pub statements: Vec<Statement<'tcx>>, |
54a0048b SL |
785 | |
786 | /// Terminator for this block. | |
787 | /// | |
788 | /// NB. This should generally ONLY be `None` during construction. | |
789 | /// Therefore, you should generally access it via the | |
790 | /// `terminator()` or `terminator_mut()` methods. The only | |
791 | /// exception is that certain passes, such as `simplify_cfg`, swap | |
792 | /// out the terminator temporarily with `None` while they continue | |
793 | /// to recurse over the set of basic blocks. | |
9cc50fc6 | 794 | pub terminator: Option<Terminator<'tcx>>, |
54a0048b SL |
795 | |
796 | /// If true, this block lies on an unwind path. This is used | |
94b46f34 | 797 | /// during codegen where distinct kinds of basic blocks may be |
54a0048b SL |
798 | /// generated (particularly for MSVC cleanup). Unwind blocks must |
799 | /// only branch to other unwind blocks. | |
9cc50fc6 | 800 | pub is_cleanup: bool, |
e9174d1e SL |
801 | } |
802 | ||
54a0048b SL |
803 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
804 | pub struct Terminator<'tcx> { | |
3157f602 | 805 | pub source_info: SourceInfo, |
94b46f34 | 806 | pub kind: TerminatorKind<'tcx>, |
54a0048b SL |
807 | } |
808 | ||
7453a54e | 809 | #[derive(Clone, RustcEncodable, RustcDecodable)] |
54a0048b | 810 | pub enum TerminatorKind<'tcx> { |
e9174d1e | 811 | /// block should have one successor in the graph; we jump there |
94b46f34 | 812 | Goto { target: BasicBlock }, |
e9174d1e | 813 | |
92a42be0 SL |
814 | /// operand evaluates to an integer; jump depending on its value |
815 | /// to one of the targets, and otherwise fallback to `otherwise` | |
816 | SwitchInt { | |
817 | /// discriminant value being tested | |
8bb4bdeb | 818 | discr: Operand<'tcx>, |
92a42be0 SL |
819 | |
820 | /// type of value being tested | |
821 | switch_ty: Ty<'tcx>, | |
822 | ||
823 | /// Possible values. The locations to branch to in each case | |
824 | /// are found in the corresponding indices from the `targets` vector. | |
0531ce1d | 825 | values: Cow<'tcx, [u128]>, |
8bb4bdeb XL |
826 | |
827 | /// Possible branch sites. The last element of this vector is used | |
cc61c64b | 828 | /// for the otherwise branch, so targets.len() == values.len() + 1 |
8bb4bdeb XL |
829 | /// should hold. |
830 | // This invariant is quite non-obvious and also could be improved. | |
831 | // One way to make this invariant is to have something like this instead: | |
832 | // | |
833 | // branches: Vec<(ConstInt, BasicBlock)>, | |
834 | // otherwise: Option<BasicBlock> // exhaustive if None | |
835 | // | |
836 | // However we’ve decided to keep this as-is until we figure a case | |
837 | // where some other approach seems to be strictly better than other. | |
b039eaaf SL |
838 | targets: Vec<BasicBlock>, |
839 | }, | |
e9174d1e | 840 | |
9cc50fc6 SL |
841 | /// Indicates that the landing pad is finished and unwinding should |
842 | /// continue. Emitted by build::scope::diverge_cleanup. | |
843 | Resume, | |
e9174d1e | 844 | |
ff7c6d11 XL |
845 | /// Indicates that the landing pad is finished and that the process |
846 | /// should abort. Used to prevent unwinding for foreign items. | |
847 | Abort, | |
848 | ||
849 | /// Indicates a normal return. The return place should have | |
850 | /// been filled in by now. This should occur at most once. | |
e9174d1e SL |
851 | Return, |
852 | ||
3157f602 XL |
853 | /// Indicates a terminator that can never be reached. |
854 | Unreachable, | |
855 | ||
ff7c6d11 | 856 | /// Drop the Place |
7453a54e | 857 | Drop { |
ff7c6d11 | 858 | location: Place<'tcx>, |
7453a54e | 859 | target: BasicBlock, |
94b46f34 | 860 | unwind: Option<BasicBlock>, |
7453a54e SL |
861 | }, |
862 | ||
ff7c6d11 | 863 | /// Drop the Place and assign the new value over it. This ensures |
2c00a5a8 | 864 | /// that the assignment to `P` occurs *even if* the destructor for |
ff7c6d11 | 865 | /// place unwinds. Its semantics are best explained by by the |
abe05a73 XL |
866 | /// elaboration: |
867 | /// | |
868 | /// ``` | |
869 | /// BB0 { | |
2c00a5a8 | 870 | /// DropAndReplace(P <- V, goto BB1, unwind BB2) |
abe05a73 XL |
871 | /// } |
872 | /// ``` | |
873 | /// | |
874 | /// becomes | |
875 | /// | |
876 | /// ``` | |
877 | /// BB0 { | |
2c00a5a8 | 878 | /// Drop(P, goto BB1, unwind BB2) |
abe05a73 XL |
879 | /// } |
880 | /// BB1 { | |
2c00a5a8 XL |
881 | /// // P is now unitialized |
882 | /// P <- V | |
abe05a73 XL |
883 | /// } |
884 | /// BB2 { | |
2c00a5a8 XL |
885 | /// // P is now unitialized -- its dtor panicked |
886 | /// P <- V | |
abe05a73 XL |
887 | /// } |
888 | /// ``` | |
3157f602 | 889 | DropAndReplace { |
ff7c6d11 | 890 | location: Place<'tcx>, |
3157f602 XL |
891 | value: Operand<'tcx>, |
892 | target: BasicBlock, | |
893 | unwind: Option<BasicBlock>, | |
894 | }, | |
895 | ||
9cc50fc6 | 896 | /// Block ends with a call of a converging function |
b039eaaf | 897 | Call { |
9cc50fc6 SL |
898 | /// The function that’s being called |
899 | func: Operand<'tcx>, | |
abe05a73 XL |
900 | /// Arguments the function is called with. |
901 | /// These are owned by the callee, which is free to modify them. | |
902 | /// This allows the memory occupied by "by-value" arguments to be | |
903 | /// reused across function calls without duplicating the contents. | |
9cc50fc6 | 904 | args: Vec<Operand<'tcx>>, |
7453a54e | 905 | /// Destination for the return value. If some, the call is converging. |
ff7c6d11 | 906 | destination: Option<(Place<'tcx>, BasicBlock)>, |
7453a54e | 907 | /// Cleanups to be done if the call unwinds. |
94b46f34 | 908 | cleanup: Option<BasicBlock>, |
b039eaaf | 909 | }, |
3157f602 XL |
910 | |
911 | /// Jump to the target if the condition has the expected value, | |
912 | /// otherwise panic with a message and a cleanup target. | |
913 | Assert { | |
914 | cond: Operand<'tcx>, | |
915 | expected: bool, | |
916 | msg: AssertMessage<'tcx>, | |
917 | target: BasicBlock, | |
94b46f34 | 918 | cleanup: Option<BasicBlock>, |
ea8adc8c XL |
919 | }, |
920 | ||
921 | /// A suspend point | |
922 | Yield { | |
923 | /// The value to return | |
924 | value: Operand<'tcx>, | |
925 | /// Where to resume to | |
926 | resume: BasicBlock, | |
927 | /// Cleanup to be done if the generator is dropped at this suspend point | |
928 | drop: Option<BasicBlock>, | |
929 | }, | |
930 | ||
931 | /// Indicates the end of the dropping of a generator | |
932 | GeneratorDrop, | |
abe05a73 | 933 | |
2c00a5a8 XL |
934 | /// A block where control flow only ever takes one real path, but borrowck |
935 | /// needs to be more conservative. | |
abe05a73 | 936 | FalseEdges { |
2c00a5a8 | 937 | /// The target normal control flow will take |
abe05a73 | 938 | real_target: BasicBlock, |
2c00a5a8 XL |
939 | /// The list of blocks control flow could conceptually take, but won't |
940 | /// in practice | |
941 | imaginary_targets: Vec<BasicBlock>, | |
942 | }, | |
943 | /// A terminator for blocks that only take one path in reality, but where we | |
944 | /// reserve the right to unwind in borrowck, even if it won't happen in practice. | |
945 | /// This can arise in infinite loops with no function calls for example. | |
946 | FalseUnwind { | |
947 | /// The target normal control flow will take | |
948 | real_target: BasicBlock, | |
949 | /// The imaginary cleanup block link. This particular path will never be taken | |
950 | /// in practice, but in order to avoid fragility we want to always | |
951 | /// consider it in borrowck. We don't want to accept programs which | |
952 | /// pass borrowck only when panic=abort or some assertions are disabled | |
953 | /// due to release vs. debug mode builds. This needs to be an Option because | |
954 | /// of the remove_noop_landing_pads and no_landing_pads passes | |
955 | unwind: Option<BasicBlock>, | |
abe05a73 | 956 | }, |
e9174d1e SL |
957 | } |
958 | ||
83c7162d XL |
959 | pub type Successors<'a> = |
960 | iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>; | |
961 | pub type SuccessorsMut<'a> = | |
962 | iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; | |
963 | ||
b039eaaf | 964 | impl<'tcx> Terminator<'tcx> { |
83c7162d | 965 | pub fn successors(&self) -> Successors { |
54a0048b SL |
966 | self.kind.successors() |
967 | } | |
968 | ||
83c7162d | 969 | pub fn successors_mut(&mut self) -> SuccessorsMut { |
54a0048b SL |
970 | self.kind.successors_mut() |
971 | } | |
ff7c6d11 XL |
972 | |
973 | pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { | |
974 | self.kind.unwind_mut() | |
975 | } | |
54a0048b SL |
976 | } |
977 | ||
978 | impl<'tcx> TerminatorKind<'tcx> { | |
94b46f34 XL |
979 | pub fn if_<'a, 'gcx>( |
980 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
981 | cond: Operand<'tcx>, | |
982 | t: BasicBlock, | |
983 | f: BasicBlock, | |
984 | ) -> TerminatorKind<'tcx> { | |
0531ce1d | 985 | static BOOL_SWITCH_FALSE: &'static [u128] = &[0]; |
8bb4bdeb XL |
986 | TerminatorKind::SwitchInt { |
987 | discr: cond, | |
988 | switch_ty: tcx.types.bool, | |
989 | values: From::from(BOOL_SWITCH_FALSE), | |
990 | targets: vec![f, t], | |
991 | } | |
992 | } | |
993 | ||
83c7162d | 994 | pub fn successors(&self) -> Successors { |
54a0048b | 995 | use self::TerminatorKind::*; |
e9174d1e | 996 | match *self { |
94b46f34 XL |
997 | Resume |
998 | | Abort | |
999 | | GeneratorDrop | |
1000 | | Return | |
1001 | | Unreachable | |
1002 | | Call { | |
1003 | destination: None, | |
1004 | cleanup: None, | |
1005 | .. | |
1006 | } => None.into_iter().chain(&[]), | |
1007 | Goto { target: ref t } | |
1008 | | Call { | |
1009 | destination: None, | |
1010 | cleanup: Some(ref t), | |
1011 | .. | |
1012 | } | |
1013 | | Call { | |
1014 | destination: Some((_, ref t)), | |
1015 | cleanup: None, | |
1016 | .. | |
1017 | } | |
1018 | | Yield { | |
1019 | resume: ref t, | |
1020 | drop: None, | |
1021 | .. | |
1022 | } | |
1023 | | DropAndReplace { | |
1024 | target: ref t, | |
1025 | unwind: None, | |
1026 | .. | |
1027 | } | |
1028 | | Drop { | |
1029 | target: ref t, | |
1030 | unwind: None, | |
1031 | .. | |
83c7162d | 1032 | } |
94b46f34 XL |
1033 | | Assert { |
1034 | target: ref t, | |
1035 | cleanup: None, | |
1036 | .. | |
83c7162d | 1037 | } |
94b46f34 XL |
1038 | | FalseUnwind { |
1039 | real_target: ref t, | |
1040 | unwind: None, | |
1041 | } => Some(t).into_iter().chain(&[]), | |
1042 | Call { | |
1043 | destination: Some((_, ref t)), | |
1044 | cleanup: Some(ref u), | |
1045 | .. | |
3157f602 | 1046 | } |
94b46f34 XL |
1047 | | Yield { |
1048 | resume: ref t, | |
1049 | drop: Some(ref u), | |
1050 | .. | |
3157f602 | 1051 | } |
94b46f34 XL |
1052 | | DropAndReplace { |
1053 | target: ref t, | |
1054 | unwind: Some(ref u), | |
1055 | .. | |
abe05a73 | 1056 | } |
94b46f34 XL |
1057 | | Drop { |
1058 | target: ref t, | |
1059 | unwind: Some(ref u), | |
1060 | .. | |
1061 | } | |
1062 | | Assert { | |
1063 | target: ref t, | |
1064 | cleanup: Some(ref u), | |
1065 | .. | |
1066 | } | |
1067 | | FalseUnwind { | |
1068 | real_target: ref t, | |
1069 | unwind: Some(ref u), | |
1070 | } => Some(t).into_iter().chain(slice::from_ref(u)), | |
1071 | SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]), | |
1072 | FalseEdges { | |
1073 | ref real_target, | |
1074 | ref imaginary_targets, | |
1075 | } => Some(real_target).into_iter().chain(&imaginary_targets[..]), | |
e9174d1e SL |
1076 | } |
1077 | } | |
92a42be0 | 1078 | |
83c7162d | 1079 | pub fn successors_mut(&mut self) -> SuccessorsMut { |
54a0048b | 1080 | use self::TerminatorKind::*; |
92a42be0 | 1081 | match *self { |
94b46f34 XL |
1082 | Resume |
1083 | | Abort | |
1084 | | GeneratorDrop | |
1085 | | Return | |
1086 | | Unreachable | |
1087 | | Call { | |
1088 | destination: None, | |
1089 | cleanup: None, | |
1090 | .. | |
1091 | } => None.into_iter().chain(&mut []), | |
1092 | Goto { target: ref mut t } | |
1093 | | Call { | |
1094 | destination: None, | |
1095 | cleanup: Some(ref mut t), | |
1096 | .. | |
1097 | } | |
1098 | | Call { | |
1099 | destination: Some((_, ref mut t)), | |
1100 | cleanup: None, | |
1101 | .. | |
1102 | } | |
1103 | | Yield { | |
1104 | resume: ref mut t, | |
1105 | drop: None, | |
1106 | .. | |
1107 | } | |
1108 | | DropAndReplace { | |
1109 | target: ref mut t, | |
1110 | unwind: None, | |
1111 | .. | |
83c7162d | 1112 | } |
94b46f34 XL |
1113 | | Drop { |
1114 | target: ref mut t, | |
1115 | unwind: None, | |
1116 | .. | |
83c7162d | 1117 | } |
94b46f34 XL |
1118 | | Assert { |
1119 | target: ref mut t, | |
1120 | cleanup: None, | |
1121 | .. | |
83c7162d | 1122 | } |
94b46f34 XL |
1123 | | FalseUnwind { |
1124 | real_target: ref mut t, | |
1125 | unwind: None, | |
1126 | } => Some(t).into_iter().chain(&mut []), | |
1127 | Call { | |
1128 | destination: Some((_, ref mut t)), | |
1129 | cleanup: Some(ref mut u), | |
1130 | .. | |
3157f602 | 1131 | } |
94b46f34 XL |
1132 | | Yield { |
1133 | resume: ref mut t, | |
1134 | drop: Some(ref mut u), | |
1135 | .. | |
abe05a73 | 1136 | } |
94b46f34 XL |
1137 | | DropAndReplace { |
1138 | target: ref mut t, | |
1139 | unwind: Some(ref mut u), | |
1140 | .. | |
1141 | } | |
1142 | | Drop { | |
1143 | target: ref mut t, | |
1144 | unwind: Some(ref mut u), | |
1145 | .. | |
1146 | } | |
1147 | | Assert { | |
1148 | target: ref mut t, | |
1149 | cleanup: Some(ref mut u), | |
1150 | .. | |
1151 | } | |
1152 | | FalseUnwind { | |
1153 | real_target: ref mut t, | |
1154 | unwind: Some(ref mut u), | |
1155 | } => Some(t).into_iter().chain(slice::from_mut(u)), | |
1156 | SwitchInt { | |
1157 | ref mut targets, .. | |
1158 | } => None.into_iter().chain(&mut targets[..]), | |
1159 | FalseEdges { | |
1160 | ref mut real_target, | |
1161 | ref mut imaginary_targets, | |
1162 | } => Some(real_target) | |
1163 | .into_iter() | |
1164 | .chain(&mut imaginary_targets[..]), | |
92a42be0 SL |
1165 | } |
1166 | } | |
ff7c6d11 XL |
1167 | |
1168 | pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { | |
1169 | match *self { | |
94b46f34 XL |
1170 | TerminatorKind::Goto { .. } |
1171 | | TerminatorKind::Resume | |
1172 | | TerminatorKind::Abort | |
1173 | | TerminatorKind::Return | |
1174 | | TerminatorKind::Unreachable | |
1175 | | TerminatorKind::GeneratorDrop | |
1176 | | TerminatorKind::Yield { .. } | |
1177 | | TerminatorKind::SwitchInt { .. } | |
1178 | | TerminatorKind::FalseEdges { .. } => None, | |
1179 | TerminatorKind::Call { | |
1180 | cleanup: ref mut unwind, | |
1181 | .. | |
1182 | } | |
1183 | | TerminatorKind::Assert { | |
1184 | cleanup: ref mut unwind, | |
1185 | .. | |
ff7c6d11 | 1186 | } |
94b46f34 XL |
1187 | | TerminatorKind::DropAndReplace { ref mut unwind, .. } |
1188 | | TerminatorKind::Drop { ref mut unwind, .. } | |
1189 | | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind), | |
ff7c6d11 XL |
1190 | } |
1191 | } | |
e9174d1e SL |
1192 | } |
1193 | ||
b039eaaf | 1194 | impl<'tcx> BasicBlockData<'tcx> { |
9cc50fc6 | 1195 | pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> { |
e9174d1e SL |
1196 | BasicBlockData { |
1197 | statements: vec![], | |
041b39d2 | 1198 | terminator, |
9cc50fc6 | 1199 | is_cleanup: false, |
e9174d1e SL |
1200 | } |
1201 | } | |
9cc50fc6 SL |
1202 | |
1203 | /// Accessor for terminator. | |
1204 | /// | |
1205 | /// Terminator may not be None after construction of the basic block is complete. This accessor | |
1206 | /// provides a convenience way to reach the terminator. | |
1207 | pub fn terminator(&self) -> &Terminator<'tcx> { | |
1208 | self.terminator.as_ref().expect("invalid terminator state") | |
1209 | } | |
1210 | ||
1211 | pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { | |
1212 | self.terminator.as_mut().expect("invalid terminator state") | |
1213 | } | |
ea8adc8c | 1214 | |
94b46f34 XL |
1215 | pub fn retain_statements<F>(&mut self, mut f: F) |
1216 | where | |
1217 | F: FnMut(&mut Statement) -> bool, | |
1218 | { | |
ea8adc8c XL |
1219 | for s in &mut self.statements { |
1220 | if !f(s) { | |
0531ce1d | 1221 | s.make_nop(); |
ea8adc8c XL |
1222 | } |
1223 | } | |
1224 | } | |
ff7c6d11 | 1225 | |
0531ce1d | 1226 | pub fn expand_statements<F, I>(&mut self, mut f: F) |
94b46f34 XL |
1227 | where |
1228 | F: FnMut(&mut Statement<'tcx>) -> Option<I>, | |
1229 | I: iter::TrustedLen<Item = Statement<'tcx>>, | |
0531ce1d XL |
1230 | { |
1231 | // Gather all the iterators we'll need to splice in, and their positions. | |
1232 | let mut splices: Vec<(usize, I)> = vec![]; | |
1233 | let mut extra_stmts = 0; | |
1234 | for (i, s) in self.statements.iter_mut().enumerate() { | |
1235 | if let Some(mut new_stmts) = f(s) { | |
1236 | if let Some(first) = new_stmts.next() { | |
1237 | // We can already store the first new statement. | |
1238 | *s = first; | |
1239 | ||
1240 | // Save the other statements for optimized splicing. | |
1241 | let remaining = new_stmts.size_hint().0; | |
1242 | if remaining > 0 { | |
1243 | splices.push((i + 1 + extra_stmts, new_stmts)); | |
1244 | extra_stmts += remaining; | |
1245 | } | |
1246 | } else { | |
1247 | s.make_nop(); | |
1248 | } | |
1249 | } | |
1250 | } | |
1251 | ||
1252 | // Splice in the new statements, from the end of the block. | |
1253 | // FIXME(eddyb) This could be more efficient with a "gap buffer" | |
1254 | // where a range of elements ("gap") is left uninitialized, with | |
1255 | // splicing adding new elements to the end of that gap and moving | |
1256 | // existing elements from before the gap to the end of the gap. | |
1257 | // For now, this is safe code, emulating a gap but initializing it. | |
94b46f34 XL |
1258 | let mut gap = self.statements.len()..self.statements.len() + extra_stmts; |
1259 | self.statements.resize( | |
1260 | gap.end, | |
1261 | Statement { | |
1262 | source_info: SourceInfo { | |
1263 | span: DUMMY_SP, | |
1264 | scope: OUTERMOST_SOURCE_SCOPE, | |
1265 | }, | |
1266 | kind: StatementKind::Nop, | |
0531ce1d | 1267 | }, |
94b46f34 | 1268 | ); |
0531ce1d XL |
1269 | for (splice_start, new_stmts) in splices.into_iter().rev() { |
1270 | let splice_end = splice_start + new_stmts.size_hint().0; | |
1271 | while gap.end > splice_end { | |
1272 | gap.start -= 1; | |
1273 | gap.end -= 1; | |
1274 | self.statements.swap(gap.start, gap.end); | |
1275 | } | |
1276 | self.statements.splice(splice_start..splice_end, new_stmts); | |
1277 | gap.end = splice_start; | |
1278 | } | |
1279 | } | |
1280 | ||
ff7c6d11 XL |
1281 | pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { |
1282 | if index < self.statements.len() { | |
1283 | &self.statements[index] | |
1284 | } else { | |
1285 | &self.terminator | |
1286 | } | |
1287 | } | |
e9174d1e SL |
1288 | } |
1289 | ||
54a0048b | 1290 | impl<'tcx> Debug for TerminatorKind<'tcx> { |
9cc50fc6 | 1291 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
54a0048b | 1292 | self.fmt_head(fmt)?; |
83c7162d | 1293 | let successor_count = self.successors().count(); |
9cc50fc6 | 1294 | let labels = self.fmt_successor_labels(); |
83c7162d | 1295 | assert_eq!(successor_count, labels.len()); |
9cc50fc6 | 1296 | |
83c7162d | 1297 | match successor_count { |
9cc50fc6 SL |
1298 | 0 => Ok(()), |
1299 | ||
83c7162d | 1300 | 1 => write!(fmt, " -> {:?}", self.successors().nth(0).unwrap()), |
9cc50fc6 SL |
1301 | |
1302 | _ => { | |
54a0048b | 1303 | write!(fmt, " -> [")?; |
83c7162d | 1304 | for (i, target) in self.successors().enumerate() { |
9cc50fc6 | 1305 | if i > 0 { |
54a0048b | 1306 | write!(fmt, ", ")?; |
9cc50fc6 | 1307 | } |
54a0048b | 1308 | write!(fmt, "{}: {:?}", labels[i], target)?; |
9cc50fc6 SL |
1309 | } |
1310 | write!(fmt, "]") | |
1311 | } | |
9cc50fc6 SL |
1312 | } |
1313 | } | |
1314 | } | |
1315 | ||
54a0048b | 1316 | impl<'tcx> TerminatorKind<'tcx> { |
9cc50fc6 | 1317 | /// Write the "head" part of the terminator; that is, its name and the data it uses to pick the |
3b2f2976 | 1318 | /// successor basic block, if any. The only information not included is the list of possible |
9cc50fc6 SL |
1319 | /// successors, which may be rendered differently between the text and the graphviz format. |
1320 | pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result { | |
54a0048b | 1321 | use self::TerminatorKind::*; |
e9174d1e | 1322 | match *self { |
9cc50fc6 | 1323 | Goto { .. } => write!(fmt, "goto"), |
94b46f34 XL |
1324 | SwitchInt { |
1325 | discr: ref place, .. | |
1326 | } => write!(fmt, "switchInt({:?})", place), | |
9cc50fc6 | 1327 | Return => write!(fmt, "return"), |
ea8adc8c | 1328 | GeneratorDrop => write!(fmt, "generator_drop"), |
9cc50fc6 | 1329 | Resume => write!(fmt, "resume"), |
ff7c6d11 | 1330 | Abort => write!(fmt, "abort"), |
ea8adc8c | 1331 | Yield { ref value, .. } => write!(fmt, "_1 = suspend({:?})", value), |
3157f602 XL |
1332 | Unreachable => write!(fmt, "unreachable"), |
1333 | Drop { ref location, .. } => write!(fmt, "drop({:?})", location), | |
94b46f34 XL |
1334 | DropAndReplace { |
1335 | ref location, | |
1336 | ref value, | |
1337 | .. | |
1338 | } => write!(fmt, "replace({:?} <- {:?})", location, value), | |
1339 | Call { | |
1340 | ref func, | |
1341 | ref args, | |
1342 | ref destination, | |
1343 | .. | |
1344 | } => { | |
7453a54e | 1345 | if let Some((ref destination, _)) = *destination { |
54a0048b | 1346 | write!(fmt, "{:?} = ", destination)?; |
9cc50fc6 | 1347 | } |
54a0048b | 1348 | write!(fmt, "{:?}(", func)?; |
9cc50fc6 | 1349 | for (index, arg) in args.iter().enumerate() { |
b039eaaf | 1350 | if index > 0 { |
54a0048b | 1351 | write!(fmt, ", ")?; |
b039eaaf | 1352 | } |
54a0048b | 1353 | write!(fmt, "{:?}", arg)?; |
e9174d1e | 1354 | } |
9cc50fc6 | 1355 | write!(fmt, ")") |
e9174d1e | 1356 | } |
94b46f34 XL |
1357 | Assert { |
1358 | ref cond, | |
1359 | expected, | |
1360 | ref msg, | |
1361 | .. | |
1362 | } => { | |
3157f602 XL |
1363 | write!(fmt, "assert(")?; |
1364 | if !expected { | |
1365 | write!(fmt, "!")?; | |
1366 | } | |
83c7162d | 1367 | write!(fmt, "{:?}, \"{:?}\")", cond, msg) |
94b46f34 | 1368 | } |
2c00a5a8 XL |
1369 | FalseEdges { .. } => write!(fmt, "falseEdges"), |
1370 | FalseUnwind { .. } => write!(fmt, "falseUnwind"), | |
e9174d1e SL |
1371 | } |
1372 | } | |
9cc50fc6 SL |
1373 | |
1374 | /// Return the list of labels for the edges to the successor basic blocks. | |
1375 | pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> { | |
54a0048b | 1376 | use self::TerminatorKind::*; |
9cc50fc6 | 1377 | match *self { |
ff7c6d11 | 1378 | Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], |
7453a54e | 1379 | Goto { .. } => vec!["".into()], |
94b46f34 XL |
1380 | SwitchInt { |
1381 | ref values, | |
1382 | switch_ty, | |
1383 | .. | |
1384 | } => { | |
1385 | let size = ty::tls::with(|tcx| { | |
1386 | let param_env = ty::ParamEnv::empty(); | |
1387 | let switch_ty = tcx.lift_to_global(&switch_ty).unwrap(); | |
1388 | tcx.layout_of(param_env.and(switch_ty)).unwrap().size | |
1389 | }); | |
1390 | values | |
1391 | .iter() | |
1392 | .map(|&u| { | |
1393 | let mut s = String::new(); | |
1394 | print_miri_value( | |
1395 | Value::Scalar(Scalar::Bits { | |
1396 | bits: u, | |
1397 | defined: size.bits() as u8, | |
1398 | }), | |
1399 | switch_ty, | |
1400 | &mut s, | |
1401 | ).unwrap(); | |
1402 | s.into() | |
1403 | }) | |
1404 | .chain(iter::once(String::from("otherwise").into())) | |
1405 | .collect() | |
9cc50fc6 | 1406 | } |
94b46f34 XL |
1407 | Call { |
1408 | destination: Some(_), | |
1409 | cleanup: Some(_), | |
1410 | .. | |
1411 | } => vec!["return".into_cow(), "unwind".into_cow()], | |
1412 | Call { | |
1413 | destination: Some(_), | |
1414 | cleanup: None, | |
1415 | .. | |
1416 | } => vec!["return".into_cow()], | |
1417 | Call { | |
1418 | destination: None, | |
1419 | cleanup: Some(_), | |
1420 | .. | |
1421 | } => vec!["unwind".into_cow()], | |
1422 | Call { | |
1423 | destination: None, | |
1424 | cleanup: None, | |
1425 | .. | |
1426 | } => vec![], | |
1427 | Yield { drop: Some(_), .. } => vec!["resume".into_cow(), "drop".into_cow()], | |
ea8adc8c | 1428 | Yield { drop: None, .. } => vec!["resume".into_cow()], |
94b46f34 XL |
1429 | DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => { |
1430 | vec!["return".into_cow()] | |
1431 | } | |
1432 | DropAndReplace { | |
1433 | unwind: Some(_), .. | |
3157f602 | 1434 | } |
94b46f34 XL |
1435 | | Drop { |
1436 | unwind: Some(_), .. | |
1437 | } => vec!["return".into_cow(), "unwind".into_cow()], | |
3157f602 | 1438 | Assert { cleanup: None, .. } => vec!["".into()], |
94b46f34 XL |
1439 | Assert { .. } => vec!["success".into_cow(), "unwind".into_cow()], |
1440 | FalseEdges { | |
1441 | ref imaginary_targets, | |
1442 | .. | |
1443 | } => { | |
abe05a73 XL |
1444 | let mut l = vec!["real".into()]; |
1445 | l.resize(imaginary_targets.len() + 1, "imaginary".into()); | |
1446 | l | |
1447 | } | |
94b46f34 XL |
1448 | FalseUnwind { |
1449 | unwind: Some(_), .. | |
1450 | } => vec!["real".into(), "cleanup".into()], | |
2c00a5a8 | 1451 | FalseUnwind { unwind: None, .. } => vec!["real".into()], |
9cc50fc6 SL |
1452 | } |
1453 | } | |
e9174d1e SL |
1454 | } |
1455 | ||
e9174d1e SL |
1456 | /////////////////////////////////////////////////////////////////////////// |
1457 | // Statements | |
1458 | ||
7453a54e | 1459 | #[derive(Clone, RustcEncodable, RustcDecodable)] |
b039eaaf | 1460 | pub struct Statement<'tcx> { |
3157f602 | 1461 | pub source_info: SourceInfo, |
b039eaaf | 1462 | pub kind: StatementKind<'tcx>, |
e9174d1e SL |
1463 | } |
1464 | ||
9e0c209e SL |
1465 | impl<'tcx> Statement<'tcx> { |
1466 | /// Changes a statement to a nop. This is both faster than deleting instructions and avoids | |
1467 | /// invalidating statement indices in `Location`s. | |
1468 | pub fn make_nop(&mut self) { | |
1469 | self.kind = StatementKind::Nop | |
1470 | } | |
0531ce1d XL |
1471 | |
1472 | /// Changes a statement to a nop and returns the original statement. | |
1473 | pub fn replace_nop(&mut self) -> Self { | |
1474 | Statement { | |
1475 | source_info: self.source_info, | |
94b46f34 | 1476 | kind: mem::replace(&mut self.kind, StatementKind::Nop), |
0531ce1d XL |
1477 | } |
1478 | } | |
9e0c209e SL |
1479 | } |
1480 | ||
7453a54e | 1481 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
b039eaaf | 1482 | pub enum StatementKind<'tcx> { |
ff7c6d11 XL |
1483 | /// Write the RHS Rvalue to the LHS Place. |
1484 | Assign(Place<'tcx>, Rvalue<'tcx>), | |
5bcae85e | 1485 | |
94b46f34 XL |
1486 | /// This represents all the reading that a pattern match may do |
1487 | /// (e.g. inspecting constants and discriminant values). | |
1488 | ReadForMatch(Place<'tcx>), | |
1489 | ||
ff7c6d11 | 1490 | /// Write the discriminant for a variant to the enum Place. |
94b46f34 XL |
1491 | SetDiscriminant { |
1492 | place: Place<'tcx>, | |
1493 | variant_index: usize, | |
1494 | }, | |
5bcae85e SL |
1495 | |
1496 | /// Start a live range for the storage of the local. | |
ea8adc8c | 1497 | StorageLive(Local), |
5bcae85e SL |
1498 | |
1499 | /// End the current live range for the storage of the local. | |
ea8adc8c | 1500 | StorageDead(Local), |
9e0c209e | 1501 | |
3b2f2976 | 1502 | /// Execute a piece of inline Assembly. |
8bb4bdeb | 1503 | InlineAsm { |
cc61c64b | 1504 | asm: Box<InlineAsm>, |
ff7c6d11 | 1505 | outputs: Vec<Place<'tcx>>, |
94b46f34 | 1506 | inputs: Vec<Operand<'tcx>>, |
8bb4bdeb XL |
1507 | }, |
1508 | ||
ff7c6d11 | 1509 | /// Assert the given places to be valid inhabitants of their type. These statements are |
3b2f2976 XL |
1510 | /// currently only interpreted by miri and only generated when "-Z mir-emit-validate" is passed. |
1511 | /// See <https://internals.rust-lang.org/t/types-as-contracts/5562/73> for more details. | |
ff7c6d11 | 1512 | Validate(ValidationOp, Vec<ValidationOperand<'tcx, Place<'tcx>>>), |
3b2f2976 | 1513 | |
ea8adc8c | 1514 | /// Mark one terminating point of a region scope (i.e. static region). |
041b39d2 | 1515 | /// (The starting point(s) arise implicitly from borrows.) |
ea8adc8c | 1516 | EndRegion(region::Scope), |
041b39d2 | 1517 | |
0531ce1d XL |
1518 | /// Encodes a user's type assertion. These need to be preserved intact so that NLL can respect |
1519 | /// them. For example: | |
1520 | /// | |
1521 | /// let (a, b): (T, U) = y; | |
1522 | /// | |
1523 | /// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y` | |
1524 | /// is the right thing. | |
1525 | /// | |
1526 | /// `CanonicalTy` is used to capture "inference variables" from the user's types. For example: | |
1527 | /// | |
1528 | /// let x: Vec<_> = ...; | |
1529 | /// let y: &u32 = ...; | |
1530 | /// | |
1531 | /// would result in `Vec<?0>` and `&'?0 u32` respectively (where `?0` is a canonicalized | |
1532 | /// variable). | |
1533 | UserAssertTy(CanonicalTy<'tcx>, Local), | |
1534 | ||
9e0c209e SL |
1535 | /// No-op. Useful for deleting instructions without affecting statement indices. |
1536 | Nop, | |
e9174d1e SL |
1537 | } |
1538 | ||
3b2f2976 XL |
1539 | /// The `ValidationOp` describes what happens with each of the operands of a |
1540 | /// `Validate` statement. | |
1541 | #[derive(Copy, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq)] | |
1542 | pub enum ValidationOp { | |
ff7c6d11 | 1543 | /// Recursively traverse the place following the type and validate that all type |
3b2f2976 | 1544 | /// invariants are maintained. Furthermore, acquire exclusive/read-only access to the |
ff7c6d11 | 1545 | /// memory reachable from the place. |
3b2f2976 XL |
1546 | Acquire, |
1547 | /// Recursive traverse the *mutable* part of the type and relinquish all exclusive | |
1548 | /// access. | |
1549 | Release, | |
1550 | /// Recursive traverse the *mutable* part of the type and relinquish all exclusive | |
1551 | /// access *until* the given region ends. Then, access will be recovered. | |
ea8adc8c | 1552 | Suspend(region::Scope), |
3b2f2976 XL |
1553 | } |
1554 | ||
1555 | impl Debug for ValidationOp { | |
1556 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { | |
1557 | use self::ValidationOp::*; | |
1558 | match *self { | |
1559 | Acquire => write!(fmt, "Acquire"), | |
1560 | Release => write!(fmt, "Release"), | |
1561 | // (reuse lifetime rendering policy from ppaux.) | |
1562 | Suspend(ref ce) => write!(fmt, "Suspend({})", ty::ReScope(*ce)), | |
1563 | } | |
1564 | } | |
1565 | } | |
1566 | ||
1567 | // This is generic so that it can be reused by miri | |
1568 | #[derive(Clone, RustcEncodable, RustcDecodable)] | |
1569 | pub struct ValidationOperand<'tcx, T> { | |
ff7c6d11 | 1570 | pub place: T, |
3b2f2976 | 1571 | pub ty: Ty<'tcx>, |
ea8adc8c | 1572 | pub re: Option<region::Scope>, |
3b2f2976 XL |
1573 | pub mutbl: hir::Mutability, |
1574 | } | |
1575 | ||
1576 | impl<'tcx, T: Debug> Debug for ValidationOperand<'tcx, T> { | |
1577 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { | |
ff7c6d11 | 1578 | write!(fmt, "{:?}: {:?}", self.place, self.ty)?; |
3b2f2976 XL |
1579 | if let Some(ce) = self.re { |
1580 | // (reuse lifetime rendering policy from ppaux.) | |
1581 | write!(fmt, "/{}", ty::ReScope(ce))?; | |
1582 | } | |
1583 | if let hir::MutImmutable = self.mutbl { | |
1584 | write!(fmt, " (imm)")?; | |
1585 | } | |
1586 | Ok(()) | |
1587 | } | |
1588 | } | |
1589 | ||
b039eaaf | 1590 | impl<'tcx> Debug for Statement<'tcx> { |
9cc50fc6 | 1591 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
e9174d1e SL |
1592 | use self::StatementKind::*; |
1593 | match self.kind { | |
ff7c6d11 | 1594 | Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv), |
94b46f34 | 1595 | ReadForMatch(ref place) => write!(fmt, "ReadForMatch({:?})", place), |
041b39d2 XL |
1596 | // (reuse lifetime rendering policy from ppaux.) |
1597 | EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)), | |
ff7c6d11 XL |
1598 | Validate(ref op, ref places) => write!(fmt, "Validate({:?}, {:?})", op, places), |
1599 | StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place), | |
1600 | StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place), | |
94b46f34 XL |
1601 | SetDiscriminant { |
1602 | ref place, | |
1603 | variant_index, | |
1604 | } => write!(fmt, "discriminant({:?}) = {:?}", place, variant_index), | |
1605 | InlineAsm { | |
1606 | ref asm, | |
1607 | ref outputs, | |
1608 | ref inputs, | |
1609 | } => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs), | |
1610 | UserAssertTy(ref c_ty, ref local) => { | |
1611 | write!(fmt, "UserAssertTy({:?}, {:?})", c_ty, local) | |
1612 | } | |
9e0c209e | 1613 | Nop => write!(fmt, "nop"), |
e9174d1e SL |
1614 | } |
1615 | } | |
1616 | } | |
54a0048b | 1617 | |
e9174d1e | 1618 | /////////////////////////////////////////////////////////////////////////// |
ff7c6d11 | 1619 | // Places |
e9174d1e SL |
1620 | |
1621 | /// A path to a value; something that can be evaluated without | |
1622 | /// changing or disturbing program state. | |
ff7c6d11 XL |
1623 | #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
1624 | pub enum Place<'tcx> { | |
c30ab7b3 SL |
1625 | /// local variable |
1626 | Local(Local), | |
e9174d1e SL |
1627 | |
1628 | /// static or static mut variable | |
8bb4bdeb | 1629 | Static(Box<Static<'tcx>>), |
e9174d1e | 1630 | |
ff7c6d11 XL |
1631 | /// projection out of a place (access a field, deref a pointer, etc) |
1632 | Projection(Box<PlaceProjection<'tcx>>), | |
e9174d1e SL |
1633 | } |
1634 | ||
8bb4bdeb XL |
1635 | /// The def-id of a static, along with its normalized type (which is |
1636 | /// stored to avoid requiring normalization when reading MIR). | |
ff7c6d11 | 1637 | #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
8bb4bdeb XL |
1638 | pub struct Static<'tcx> { |
1639 | pub def_id: DefId, | |
1640 | pub ty: Ty<'tcx>, | |
1641 | } | |
1642 | ||
cc61c64b XL |
1643 | impl_stable_hash_for!(struct Static<'tcx> { |
1644 | def_id, | |
1645 | ty | |
1646 | }); | |
1647 | ||
e9174d1e SL |
1648 | /// The `Projection` data structure defines things of the form `B.x` |
1649 | /// or `*B` or `B[index]`. Note that it is parameterized because it is | |
ff7c6d11 XL |
1650 | /// shared between `Constant` and `Place`. See the aliases |
1651 | /// `PlaceProjection` etc below. | |
54a0048b | 1652 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
3b2f2976 | 1653 | pub struct Projection<'tcx, B, V, T> { |
e9174d1e | 1654 | pub base: B, |
3b2f2976 | 1655 | pub elem: ProjectionElem<'tcx, V, T>, |
e9174d1e SL |
1656 | } |
1657 | ||
54a0048b | 1658 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
3b2f2976 | 1659 | pub enum ProjectionElem<'tcx, V, T> { |
e9174d1e | 1660 | Deref, |
3b2f2976 | 1661 | Field(Field, T), |
e9174d1e SL |
1662 | Index(V), |
1663 | ||
7453a54e SL |
1664 | /// These indices are generated by slice patterns. Easiest to explain |
1665 | /// by example: | |
1666 | /// | |
1667 | /// ``` | |
1668 | /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, | |
1669 | /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, | |
1670 | /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, | |
1671 | /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, | |
1672 | /// ``` | |
e9174d1e | 1673 | ConstantIndex { |
7453a54e SL |
1674 | /// index or -index (in Python terms), depending on from_end |
1675 | offset: u32, | |
1676 | /// thing being indexed must be at least this long | |
1677 | min_length: u32, | |
1678 | /// counting backwards from end? | |
1679 | from_end: bool, | |
e9174d1e SL |
1680 | }, |
1681 | ||
3157f602 XL |
1682 | /// These indices are generated by slice patterns. |
1683 | /// | |
1684 | /// slice[from:-to] in Python terms. | |
1685 | Subslice { | |
1686 | from: u32, | |
1687 | to: u32, | |
1688 | }, | |
1689 | ||
7453a54e SL |
1690 | /// "Downcast" to a variant of an ADT. Currently, we only introduce |
1691 | /// this for ADTs with more than one variant. It may be better to | |
1692 | /// just introduce it always, or always for enums. | |
476ff2be | 1693 | Downcast(&'tcx AdtDef, usize), |
e9174d1e SL |
1694 | } |
1695 | ||
ff7c6d11 | 1696 | /// Alias for projections as they appear in places, where the base is a place |
ea8adc8c | 1697 | /// and the index is a local. |
ff7c6d11 | 1698 | pub type PlaceProjection<'tcx> = Projection<'tcx, Place<'tcx>, Local, Ty<'tcx>>; |
e9174d1e | 1699 | |
ff7c6d11 | 1700 | /// Alias for projections as they appear in places, where the base is a place |
ea8adc8c | 1701 | /// and the index is a local. |
ff7c6d11 | 1702 | pub type PlaceElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>; |
e9174d1e | 1703 | |
abe05a73 | 1704 | newtype_index!(Field { DEBUG_FORMAT = "field[{}]" }); |
e9174d1e | 1705 | |
ff7c6d11 XL |
1706 | impl<'tcx> Place<'tcx> { |
1707 | pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> { | |
7453a54e | 1708 | self.elem(ProjectionElem::Field(f, ty)) |
e9174d1e SL |
1709 | } |
1710 | ||
ff7c6d11 | 1711 | pub fn deref(self) -> Place<'tcx> { |
e9174d1e SL |
1712 | self.elem(ProjectionElem::Deref) |
1713 | } | |
1714 | ||
ff7c6d11 | 1715 | pub fn downcast(self, adt_def: &'tcx AdtDef, variant_index: usize) -> Place<'tcx> { |
32a655c1 SL |
1716 | self.elem(ProjectionElem::Downcast(adt_def, variant_index)) |
1717 | } | |
1718 | ||
ff7c6d11 | 1719 | pub fn index(self, index: Local) -> Place<'tcx> { |
e9174d1e SL |
1720 | self.elem(ProjectionElem::Index(index)) |
1721 | } | |
1722 | ||
ff7c6d11 | 1723 | pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> { |
94b46f34 | 1724 | Place::Projection(Box::new(PlaceProjection { base: self, elem })) |
e9174d1e SL |
1725 | } |
1726 | } | |
1727 | ||
ff7c6d11 | 1728 | impl<'tcx> Debug for Place<'tcx> { |
9cc50fc6 | 1729 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
ff7c6d11 | 1730 | use self::Place::*; |
e9174d1e SL |
1731 | |
1732 | match *self { | |
c30ab7b3 | 1733 | Local(id) => write!(fmt, "{:?}", id), |
94b46f34 XL |
1734 | Static(box self::Static { def_id, ty }) => write!( |
1735 | fmt, | |
1736 | "({}: {:?})", | |
1737 | ty::tls::with(|tcx| tcx.item_path_str(def_id)), | |
1738 | ty | |
1739 | ), | |
1740 | Projection(ref data) => match data.elem { | |
1741 | ProjectionElem::Downcast(ref adt_def, index) => { | |
1742 | write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name) | |
1743 | } | |
1744 | ProjectionElem::Deref => write!(fmt, "(*{:?})", data.base), | |
1745 | ProjectionElem::Field(field, ty) => { | |
1746 | write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty) | |
1747 | } | |
1748 | ProjectionElem::Index(ref index) => write!(fmt, "{:?}[{:?}]", data.base, index), | |
1749 | ProjectionElem::ConstantIndex { | |
1750 | offset, | |
1751 | min_length, | |
1752 | from_end: false, | |
1753 | } => write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length), | |
1754 | ProjectionElem::ConstantIndex { | |
1755 | offset, | |
1756 | min_length, | |
1757 | from_end: true, | |
1758 | } => write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length), | |
1759 | ProjectionElem::Subslice { from, to } if to == 0 => { | |
1760 | write!(fmt, "{:?}[{:?}:]", data.base, from) | |
1761 | } | |
1762 | ProjectionElem::Subslice { from, to } if from == 0 => { | |
1763 | write!(fmt, "{:?}[:-{:?}]", data.base, to) | |
1764 | } | |
1765 | ProjectionElem::Subslice { from, to } => { | |
1766 | write!(fmt, "{:?}[{:?}:-{:?}]", data.base, from, to) | |
1767 | } | |
1768 | }, | |
e9174d1e SL |
1769 | } |
1770 | } | |
1771 | } | |
1772 | ||
54a0048b SL |
1773 | /////////////////////////////////////////////////////////////////////////// |
1774 | // Scopes | |
1775 | ||
94b46f34 | 1776 | newtype_index!(SourceScope |
abe05a73 XL |
1777 | { |
1778 | DEBUG_FORMAT = "scope[{}]", | |
94b46f34 | 1779 | const OUTERMOST_SOURCE_SCOPE = 0, |
abe05a73 | 1780 | }); |
54a0048b SL |
1781 | |
1782 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
94b46f34 | 1783 | pub struct SourceScopeData { |
a7813a04 | 1784 | pub span: Span, |
94b46f34 XL |
1785 | pub parent_scope: Option<SourceScope>, |
1786 | } | |
1787 | ||
1788 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
1789 | pub struct SourceScopeLocalData { | |
1790 | /// A NodeId with lint levels equivalent to this scope's lint levels. | |
1791 | pub lint_root: ast::NodeId, | |
1792 | /// The unsafe block that contains this node. | |
1793 | pub safety: Safety, | |
54a0048b SL |
1794 | } |
1795 | ||
e9174d1e SL |
1796 | /////////////////////////////////////////////////////////////////////////// |
1797 | // Operands | |
54a0048b | 1798 | |
7453a54e | 1799 | /// These are values that can appear inside an rvalue (or an index |
ff7c6d11 | 1800 | /// place). They are intentionally limited to prevent rvalues from |
7453a54e | 1801 | /// being nested in one another. |
9cc50fc6 | 1802 | #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] |
b039eaaf | 1803 | pub enum Operand<'tcx> { |
ff7c6d11 XL |
1804 | /// Copy: The value must be available for use afterwards. |
1805 | /// | |
1806 | /// This implies that the type of the place must be `Copy`; this is true | |
1807 | /// by construction during build, but also checked by the MIR type checker. | |
1808 | Copy(Place<'tcx>), | |
1809 | /// Move: The value (including old borrows of it) will not be used again. | |
1810 | /// | |
1811 | /// Safe for values of all types (modulo future developments towards `?Move`). | |
1812 | /// Correct usage patterns are enforced by the borrow checker for safe code. | |
1813 | /// `Copy` may be converted to `Move` to enable "last-use" optimizations. | |
1814 | Move(Place<'tcx>), | |
cc61c64b | 1815 | Constant(Box<Constant<'tcx>>), |
e9174d1e SL |
1816 | } |
1817 | ||
b039eaaf | 1818 | impl<'tcx> Debug for Operand<'tcx> { |
9cc50fc6 | 1819 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
e9174d1e SL |
1820 | use self::Operand::*; |
1821 | match *self { | |
1822 | Constant(ref a) => write!(fmt, "{:?}", a), | |
ff7c6d11 XL |
1823 | Copy(ref place) => write!(fmt, "{:?}", place), |
1824 | Move(ref place) => write!(fmt, "move {:?}", place), | |
e9174d1e SL |
1825 | } |
1826 | } | |
1827 | } | |
1828 | ||
cc61c64b XL |
1829 | impl<'tcx> Operand<'tcx> { |
1830 | pub fn function_handle<'a>( | |
ea8adc8c | 1831 | tcx: TyCtxt<'a, 'tcx, 'tcx>, |
cc61c64b XL |
1832 | def_id: DefId, |
1833 | substs: &'tcx Substs<'tcx>, | |
1834 | span: Span, | |
1835 | ) -> Self { | |
ea8adc8c | 1836 | let ty = tcx.type_of(def_id).subst(tcx, substs); |
cc61c64b | 1837 | Operand::Constant(box Constant { |
041b39d2 | 1838 | span, |
ea8adc8c XL |
1839 | ty, |
1840 | literal: Literal::Value { | |
94b46f34 | 1841 | value: ty::Const::zero_sized(tcx, ty), |
ea8adc8c | 1842 | }, |
cc61c64b XL |
1843 | }) |
1844 | } | |
1845 | ||
ff7c6d11 XL |
1846 | pub fn to_copy(&self) -> Self { |
1847 | match *self { | |
1848 | Operand::Copy(_) | Operand::Constant(_) => self.clone(), | |
94b46f34 | 1849 | Operand::Move(ref place) => Operand::Copy(place.clone()), |
ff7c6d11 XL |
1850 | } |
1851 | } | |
cc61c64b XL |
1852 | } |
1853 | ||
e9174d1e | 1854 | /////////////////////////////////////////////////////////////////////////// |
7453a54e | 1855 | /// Rvalues |
e9174d1e | 1856 | |
9cc50fc6 | 1857 | #[derive(Clone, RustcEncodable, RustcDecodable)] |
b039eaaf | 1858 | pub enum Rvalue<'tcx> { |
7453a54e | 1859 | /// x (either a move or copy, depending on type of x) |
b039eaaf | 1860 | Use(Operand<'tcx>), |
e9174d1e | 1861 | |
7453a54e | 1862 | /// [x; 32] |
0531ce1d | 1863 | Repeat(Operand<'tcx>, u64), |
e9174d1e | 1864 | |
7453a54e | 1865 | /// &x or &mut x |
ff7c6d11 | 1866 | Ref(Region<'tcx>, BorrowKind, Place<'tcx>), |
e9174d1e | 1867 | |
7453a54e | 1868 | /// length of a [X] or [X;n] value |
ff7c6d11 | 1869 | Len(Place<'tcx>), |
e9174d1e | 1870 | |
b039eaaf | 1871 | Cast(CastKind, Operand<'tcx>, Ty<'tcx>), |
e9174d1e | 1872 | |
b039eaaf | 1873 | BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), |
3157f602 | 1874 | CheckedBinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), |
e9174d1e | 1875 | |
7cac9316 | 1876 | NullaryOp(NullOp, Ty<'tcx>), |
b039eaaf | 1877 | UnaryOp(UnOp, Operand<'tcx>), |
e9174d1e | 1878 | |
8bb4bdeb XL |
1879 | /// Read the discriminant of an ADT. |
1880 | /// | |
1881 | /// Undefined (i.e. no effort is made to make it defined, but there’s no reason why it cannot | |
1882 | /// be defined to return, say, a 0) if ADT is not an enum. | |
ff7c6d11 | 1883 | Discriminant(Place<'tcx>), |
8bb4bdeb | 1884 | |
7453a54e SL |
1885 | /// Create an aggregate value, like a tuple or struct. This is |
1886 | /// only needed because we want to distinguish `dest = Foo { x: | |
1887 | /// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case | |
1888 | /// that `Foo` has a destructor. These rvalues can be optimized | |
1889 | /// away after type-checking and before lowering. | |
cc61c64b | 1890 | Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), |
e9174d1e SL |
1891 | } |
1892 | ||
7453a54e | 1893 | #[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
1894 | pub enum CastKind { |
1895 | Misc, | |
1896 | ||
1897 | /// Convert unique, zero-sized type for a fn to fn() | |
1898 | ReifyFnPointer, | |
1899 | ||
8bb4bdeb XL |
1900 | /// Convert non capturing closure to fn() |
1901 | ClosureFnPointer, | |
1902 | ||
e9174d1e SL |
1903 | /// Convert safe fn() to unsafe fn() |
1904 | UnsafeFnPointer, | |
1905 | ||
1906 | /// "Unsize" -- convert a thin-or-fat pointer to a fat pointer. | |
94b46f34 | 1907 | /// codegen must figure out the details once full monomorphization |
e9174d1e SL |
1908 | /// is known. For example, this could be used to cast from a |
1909 | /// `&[i32;N]` to a `&[i32]`, or a `Box<T>` to a `Box<Trait>` | |
1910 | /// (presuming `T: Trait`). | |
1911 | Unsize, | |
1912 | } | |
1913 | ||
9cc50fc6 | 1914 | #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
b039eaaf | 1915 | pub enum AggregateKind<'tcx> { |
8bb4bdeb XL |
1916 | /// The type is of the element |
1917 | Array(Ty<'tcx>), | |
e9174d1e | 1918 | Tuple, |
ff7c6d11 | 1919 | |
2c00a5a8 XL |
1920 | /// The second field is the variant index. It's equal to 0 for struct |
1921 | /// and union expressions. The fourth field is | |
ff7c6d11 XL |
1922 | /// active field number and is present only for union expressions |
1923 | /// -- e.g. for a union expression `SomeUnion { c: .. }`, the | |
1924 | /// active field index would identity the field `c` | |
476ff2be | 1925 | Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<usize>), |
ff7c6d11 | 1926 | |
a7813a04 | 1927 | Closure(DefId, ClosureSubsts<'tcx>), |
94b46f34 | 1928 | Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), |
e9174d1e SL |
1929 | } |
1930 | ||
9cc50fc6 | 1931 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
1932 | pub enum BinOp { |
1933 | /// The `+` operator (addition) | |
1934 | Add, | |
1935 | /// The `-` operator (subtraction) | |
1936 | Sub, | |
1937 | /// The `*` operator (multiplication) | |
1938 | Mul, | |
1939 | /// The `/` operator (division) | |
1940 | Div, | |
1941 | /// The `%` operator (modulus) | |
1942 | Rem, | |
1943 | /// The `^` operator (bitwise xor) | |
1944 | BitXor, | |
1945 | /// The `&` operator (bitwise and) | |
1946 | BitAnd, | |
1947 | /// The `|` operator (bitwise or) | |
1948 | BitOr, | |
1949 | /// The `<<` operator (shift left) | |
1950 | Shl, | |
1951 | /// The `>>` operator (shift right) | |
1952 | Shr, | |
1953 | /// The `==` operator (equality) | |
1954 | Eq, | |
1955 | /// The `<` operator (less than) | |
1956 | Lt, | |
1957 | /// The `<=` operator (less than or equal to) | |
1958 | Le, | |
1959 | /// The `!=` operator (not equal to) | |
1960 | Ne, | |
1961 | /// The `>=` operator (greater than or equal to) | |
1962 | Ge, | |
1963 | /// The `>` operator (greater than) | |
1964 | Gt, | |
7cac9316 XL |
1965 | /// The `ptr.offset` operator |
1966 | Offset, | |
e9174d1e SL |
1967 | } |
1968 | ||
3157f602 XL |
1969 | impl BinOp { |
1970 | pub fn is_checkable(self) -> bool { | |
1971 | use self::BinOp::*; | |
1972 | match self { | |
1973 | Add | Sub | Mul | Shl | Shr => true, | |
94b46f34 | 1974 | _ => false, |
3157f602 XL |
1975 | } |
1976 | } | |
1977 | } | |
1978 | ||
7cac9316 XL |
1979 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
1980 | pub enum NullOp { | |
1981 | /// Return the size of a value of that type | |
1982 | SizeOf, | |
1983 | /// Create a new uninitialized box for a value of that type | |
1984 | Box, | |
1985 | } | |
1986 | ||
9cc50fc6 | 1987 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
1988 | pub enum UnOp { |
1989 | /// The `!` operator for logical inversion | |
1990 | Not, | |
1991 | /// The `-` operator for negation | |
b039eaaf | 1992 | Neg, |
e9174d1e SL |
1993 | } |
1994 | ||
b039eaaf | 1995 | impl<'tcx> Debug for Rvalue<'tcx> { |
9cc50fc6 | 1996 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
e9174d1e SL |
1997 | use self::Rvalue::*; |
1998 | ||
1999 | match *self { | |
ff7c6d11 | 2000 | Use(ref place) => write!(fmt, "{:?}", place), |
e9174d1e | 2001 | Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b), |
9cc50fc6 | 2002 | Len(ref a) => write!(fmt, "Len({:?})", a), |
ff7c6d11 XL |
2003 | Cast(ref kind, ref place, ref ty) => { |
2004 | write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind) | |
2005 | } | |
9cc50fc6 | 2006 | BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b), |
3157f602 XL |
2007 | CheckedBinaryOp(ref op, ref a, ref b) => { |
2008 | write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b) | |
2009 | } | |
e9174d1e | 2010 | UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), |
ff7c6d11 | 2011 | Discriminant(ref place) => write!(fmt, "discriminant({:?})", place), |
7cac9316 | 2012 | NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), |
ff7c6d11 | 2013 | Ref(region, borrow_kind, ref place) => { |
9cc50fc6 SL |
2014 | let kind_str = match borrow_kind { |
2015 | BorrowKind::Shared => "", | |
2c00a5a8 | 2016 | BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", |
9cc50fc6 | 2017 | }; |
041b39d2 | 2018 | |
3b2f2976 XL |
2019 | // When printing regions, add trailing space if necessary. |
2020 | let region = if ppaux::verbose() || ppaux::identify_regions() { | |
041b39d2 | 2021 | let mut region = format!("{}", region); |
94b46f34 XL |
2022 | if region.len() > 0 { |
2023 | region.push(' '); | |
2024 | } | |
041b39d2 XL |
2025 | region |
2026 | } else { | |
3b2f2976 | 2027 | // Do not even print 'static |
041b39d2 XL |
2028 | "".to_owned() |
2029 | }; | |
ff7c6d11 | 2030 | write!(fmt, "&{}{}{:?}", region, kind_str, place) |
9cc50fc6 SL |
2031 | } |
2032 | ||
ff7c6d11 XL |
2033 | Aggregate(ref kind, ref places) => { |
2034 | fn fmt_tuple(fmt: &mut Formatter, places: &[Operand]) -> fmt::Result { | |
54a0048b | 2035 | let mut tuple_fmt = fmt.debug_tuple(""); |
ff7c6d11 XL |
2036 | for place in places { |
2037 | tuple_fmt.field(place); | |
9cc50fc6 SL |
2038 | } |
2039 | tuple_fmt.finish() | |
2040 | } | |
2041 | ||
cc61c64b | 2042 | match **kind { |
ff7c6d11 | 2043 | AggregateKind::Array(_) => write!(fmt, "{:?}", places), |
9cc50fc6 | 2044 | |
94b46f34 XL |
2045 | AggregateKind::Tuple => match places.len() { |
2046 | 0 => write!(fmt, "()"), | |
2047 | 1 => write!(fmt, "({:?},)", places[0]), | |
2048 | _ => fmt_tuple(fmt, places), | |
2049 | }, | |
9cc50fc6 | 2050 | |
c30ab7b3 | 2051 | AggregateKind::Adt(adt_def, variant, substs, _) => { |
9cc50fc6 | 2052 | let variant_def = &adt_def.variants[variant]; |
54a0048b | 2053 | |
9e0c209e | 2054 | ppaux::parameterized(fmt, substs, variant_def.did, &[])?; |
9cc50fc6 | 2055 | |
c30ab7b3 SL |
2056 | match variant_def.ctor_kind { |
2057 | CtorKind::Const => Ok(()), | |
ff7c6d11 | 2058 | CtorKind::Fn => fmt_tuple(fmt, places), |
c30ab7b3 | 2059 | CtorKind::Fictive => { |
54a0048b | 2060 | let mut struct_fmt = fmt.debug_struct(""); |
ff7c6d11 | 2061 | for (field, place) in variant_def.fields.iter().zip(places) { |
94b46f34 | 2062 | struct_fmt.field(&field.ident.as_str(), place); |
9cc50fc6 SL |
2063 | } |
2064 | struct_fmt.finish() | |
2065 | } | |
2066 | } | |
2067 | } | |
2068 | ||
c30ab7b3 | 2069 | AggregateKind::Closure(def_id, _) => ty::tls::with(|tcx| { |
32a655c1 | 2070 | if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { |
041b39d2 XL |
2071 | let name = if tcx.sess.opts.debugging_opts.span_free_formats { |
2072 | format!("[closure@{:?}]", node_id) | |
2073 | } else { | |
2074 | format!("[closure@{:?}]", tcx.hir.span(node_id)) | |
2075 | }; | |
9cc50fc6 SL |
2076 | let mut struct_fmt = fmt.debug_struct(&name); |
2077 | ||
2078 | tcx.with_freevars(node_id, |freevars| { | |
ff7c6d11 | 2079 | for (freevar, place) in freevars.iter().zip(places) { |
ea8adc8c | 2080 | let var_name = tcx.hir.name(freevar.var_id()); |
ff7c6d11 | 2081 | struct_fmt.field(&var_name.as_str(), place); |
9cc50fc6 SL |
2082 | } |
2083 | }); | |
2084 | ||
2085 | struct_fmt.finish() | |
2086 | } else { | |
2087 | write!(fmt, "[closure]") | |
2088 | } | |
2089 | }), | |
ea8adc8c XL |
2090 | |
2091 | AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| { | |
2092 | if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { | |
2093 | let name = format!("[generator@{:?}]", tcx.hir.span(node_id)); | |
2094 | let mut struct_fmt = fmt.debug_struct(&name); | |
2095 | ||
2096 | tcx.with_freevars(node_id, |freevars| { | |
ff7c6d11 | 2097 | for (freevar, place) in freevars.iter().zip(places) { |
ea8adc8c | 2098 | let var_name = tcx.hir.name(freevar.var_id()); |
ff7c6d11 | 2099 | struct_fmt.field(&var_name.as_str(), place); |
ea8adc8c | 2100 | } |
ff7c6d11 XL |
2101 | struct_fmt.field("$state", &places[freevars.len()]); |
2102 | for i in (freevars.len() + 1)..places.len() { | |
94b46f34 XL |
2103 | struct_fmt |
2104 | .field(&format!("${}", i - freevars.len() - 1), &places[i]); | |
ea8adc8c XL |
2105 | } |
2106 | }); | |
2107 | ||
2108 | struct_fmt.finish() | |
2109 | } else { | |
2110 | write!(fmt, "[generator]") | |
2111 | } | |
2112 | }), | |
9cc50fc6 SL |
2113 | } |
2114 | } | |
e9174d1e SL |
2115 | } |
2116 | } | |
2117 | } | |
2118 | ||
2119 | /////////////////////////////////////////////////////////////////////////// | |
7453a54e SL |
2120 | /// Constants |
2121 | /// | |
2122 | /// Two constants are equal if they are the same constant. Note that | |
2123 | /// this does not necessarily mean that they are "==" in Rust -- in | |
2124 | /// particular one must be wary of `NaN`! | |
e9174d1e | 2125 | |
54a0048b | 2126 | #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
b039eaaf SL |
2127 | pub struct Constant<'tcx> { |
2128 | pub span: Span, | |
2129 | pub ty: Ty<'tcx>, | |
2130 | pub literal: Literal<'tcx>, | |
e9174d1e SL |
2131 | } |
2132 | ||
abe05a73 XL |
2133 | newtype_index!(Promoted { DEBUG_FORMAT = "promoted[{}]" }); |
2134 | ||
54a0048b | 2135 | #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
b039eaaf | 2136 | pub enum Literal<'tcx> { |
b039eaaf | 2137 | Value { |
ea8adc8c | 2138 | value: &'tcx ty::Const<'tcx>, |
b039eaaf | 2139 | }, |
a7813a04 XL |
2140 | Promoted { |
2141 | // Index into the `promoted` vector of `Mir`. | |
94b46f34 | 2142 | index: Promoted, |
a7813a04 | 2143 | }, |
e9174d1e | 2144 | } |
9cc50fc6 SL |
2145 | |
2146 | impl<'tcx> Debug for Constant<'tcx> { | |
2147 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { | |
2148 | write!(fmt, "{:?}", self.literal) | |
2149 | } | |
2150 | } | |
2151 | ||
2152 | impl<'tcx> Debug for Literal<'tcx> { | |
2153 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { | |
2154 | use self::Literal::*; | |
2155 | match *self { | |
ea8adc8c | 2156 | Value { value } => { |
54a0048b | 2157 | write!(fmt, "const ")?; |
0531ce1d | 2158 | fmt_const_val(fmt, value) |
9cc50fc6 | 2159 | } |
94b46f34 | 2160 | Promoted { index } => write!(fmt, "{:?}", index), |
9cc50fc6 SL |
2161 | } |
2162 | } | |
2163 | } | |
2164 | ||
2165 | /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. | |
94b46f34 XL |
2166 | pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { |
2167 | use middle::const_val::ConstVal; | |
0531ce1d | 2168 | match const_val.val { |
94b46f34 XL |
2169 | ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val), |
2170 | ConstVal::Value(val) => { | |
2171 | if let Some(value) = val.to_byval_value() { | |
2172 | print_miri_value(value, const_val.ty, fmt) | |
2173 | } else { | |
2174 | write!(fmt, "{:?}:{}", val, const_val.ty) | |
2175 | } | |
2176 | } | |
0531ce1d XL |
2177 | } |
2178 | } | |
2179 | ||
2180 | pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result { | |
2181 | use ty::TypeVariants::*; | |
0531ce1d | 2182 | match (value, &ty.sty) { |
94b46f34 XL |
2183 | (Value::Scalar(Scalar::Bits { bits: 0, .. }), &TyBool) => write!(f, "false"), |
2184 | (Value::Scalar(Scalar::Bits { bits: 1, .. }), &TyBool) => write!(f, "true"), | |
2185 | (Value::Scalar(Scalar::Bits { bits, .. }), &TyFloat(ast::FloatTy::F32)) => { | |
2186 | write!(f, "{}f32", Single::from_bits(bits)) | |
2187 | } | |
2188 | (Value::Scalar(Scalar::Bits { bits, .. }), &TyFloat(ast::FloatTy::F64)) => { | |
2189 | write!(f, "{}f64", Double::from_bits(bits)) | |
2190 | } | |
2191 | (Value::Scalar(Scalar::Bits { bits, .. }), &TyUint(ui)) => write!(f, "{:?}{}", bits, ui), | |
2192 | (Value::Scalar(Scalar::Bits { bits, .. }), &TyInt(i)) => { | |
2193 | let bit_width = ty::tls::with(|tcx| { | |
2194 | let ty = tcx.lift_to_global(&ty).unwrap(); | |
2195 | tcx.layout_of(ty::ParamEnv::empty().and(ty)) | |
2196 | .unwrap() | |
2197 | .size | |
2198 | .bits() | |
2199 | }); | |
2200 | let shift = 128 - bit_width; | |
2201 | write!(f, "{:?}{}", ((bits as i128) << shift) >> shift, i) | |
2202 | } | |
2203 | (Value::Scalar(Scalar::Bits { bits, .. }), &TyChar) => { | |
2204 | write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()) | |
2205 | } | |
2206 | (_, &TyFnDef(did, _)) => write!(f, "{}", item_path_str(did)), | |
2207 | ( | |
2208 | Value::ScalarPair(Scalar::Ptr(ptr), Scalar::Bits { bits: len, .. }), | |
2209 | &TyRef(_, &ty::TyS { sty: TyStr, .. }, _), | |
2210 | ) => ty::tls::with(|tcx| match tcx.alloc_map.lock().get(ptr.alloc_id) { | |
2211 | Some(interpret::AllocType::Memory(alloc)) => { | |
2212 | assert_eq!(len as usize as u128, len); | |
2213 | let slice = &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; | |
2214 | let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); | |
2215 | write!(f, "{:?}", s) | |
2216 | } | |
2217 | _ => write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len), | |
2218 | }), | |
0531ce1d | 2219 | _ => write!(f, "{:?}:{}", value, ty), |
9cc50fc6 SL |
2220 | } |
2221 | } | |
2222 | ||
9cc50fc6 SL |
2223 | fn item_path_str(def_id: DefId) -> String { |
2224 | ty::tls::with(|tcx| tcx.item_path_str(def_id)) | |
2225 | } | |
3157f602 XL |
2226 | |
2227 | impl<'tcx> ControlFlowGraph for Mir<'tcx> { | |
3157f602 XL |
2228 | type Node = BasicBlock; |
2229 | ||
94b46f34 XL |
2230 | fn num_nodes(&self) -> usize { |
2231 | self.basic_blocks.len() | |
2232 | } | |
3157f602 | 2233 | |
94b46f34 XL |
2234 | fn start_node(&self) -> Self::Node { |
2235 | START_BLOCK | |
2236 | } | |
3157f602 | 2237 | |
94b46f34 XL |
2238 | fn predecessors<'graph>( |
2239 | &'graph self, | |
2240 | node: Self::Node, | |
2241 | ) -> <Self as GraphPredecessors<'graph>>::Iter { | |
3157f602 XL |
2242 | self.predecessors_for(node).clone().into_iter() |
2243 | } | |
94b46f34 XL |
2244 | fn successors<'graph>( |
2245 | &'graph self, | |
2246 | node: Self::Node, | |
2247 | ) -> <Self as GraphSuccessors<'graph>>::Iter { | |
83c7162d | 2248 | self.basic_blocks[node].terminator().successors().cloned() |
3157f602 XL |
2249 | } |
2250 | } | |
2251 | ||
2252 | impl<'a, 'b> GraphPredecessors<'b> for Mir<'a> { | |
2253 | type Item = BasicBlock; | |
2254 | type Iter = IntoIter<BasicBlock>; | |
2255 | } | |
2256 | ||
94b46f34 | 2257 | impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> { |
3157f602 | 2258 | type Item = BasicBlock; |
83c7162d | 2259 | type Iter = iter::Cloned<Successors<'b>>; |
3157f602 | 2260 | } |
9e0c209e SL |
2261 | |
2262 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] | |
2263 | pub struct Location { | |
2264 | /// the location is within this block | |
2265 | pub block: BasicBlock, | |
2266 | ||
2c00a5a8 | 2267 | /// the location is the start of the statement; or, if `statement_index` |
9e0c209e SL |
2268 | /// == num-statements, then the start of the terminator. |
2269 | pub statement_index: usize, | |
2270 | } | |
2271 | ||
2272 | impl fmt::Debug for Location { | |
2273 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
2274 | write!(fmt, "{:?}[{}]", self.block, self.statement_index) | |
2275 | } | |
2276 | } | |
2277 | ||
2278 | impl Location { | |
83c7162d XL |
2279 | pub const START: Location = Location { |
2280 | block: START_BLOCK, | |
2281 | statement_index: 0, | |
2282 | }; | |
2283 | ||
abe05a73 XL |
2284 | /// Returns the location immediately after this one within the enclosing block. |
2285 | /// | |
2286 | /// Note that if this location represents a terminator, then the | |
2287 | /// resulting location would be out of bounds and invalid. | |
2288 | pub fn successor_within_block(&self) -> Location { | |
94b46f34 XL |
2289 | Location { |
2290 | block: self.block, | |
2291 | statement_index: self.statement_index + 1, | |
2292 | } | |
abe05a73 XL |
2293 | } |
2294 | ||
83c7162d | 2295 | pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool { |
9e0c209e SL |
2296 | if self.block == other.block { |
2297 | self.statement_index <= other.statement_index | |
2298 | } else { | |
2299 | dominators.is_dominated_by(other.block, self.block) | |
2300 | } | |
2301 | } | |
2302 | } | |
8bb4bdeb | 2303 | |
ff7c6d11 XL |
2304 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
2305 | pub enum UnsafetyViolationKind { | |
2306 | General, | |
2307 | ExternStatic(ast::NodeId), | |
2308 | BorrowPacked(ast::NodeId), | |
2309 | } | |
2310 | ||
2311 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] | |
ea8adc8c XL |
2312 | pub struct UnsafetyViolation { |
2313 | pub source_info: SourceInfo, | |
ff7c6d11 XL |
2314 | pub description: InternedString, |
2315 | pub kind: UnsafetyViolationKind, | |
ea8adc8c XL |
2316 | } |
2317 | ||
ff7c6d11 | 2318 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
ea8adc8c XL |
2319 | pub struct UnsafetyCheckResult { |
2320 | /// Violations that are propagated *upwards* from this function | |
0531ce1d | 2321 | pub violations: Lrc<[UnsafetyViolation]>, |
ea8adc8c XL |
2322 | /// unsafe blocks in this function, along with whether they are used. This is |
2323 | /// used for the "unused_unsafe" lint. | |
0531ce1d | 2324 | pub unsafe_blocks: Lrc<[(ast::NodeId, bool)]>, |
ea8adc8c XL |
2325 | } |
2326 | ||
2327 | /// The layout of generator state | |
2328 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
2329 | pub struct GeneratorLayout<'tcx> { | |
2330 | pub fields: Vec<LocalDecl<'tcx>>, | |
2331 | } | |
8bb4bdeb | 2332 | |
83c7162d XL |
2333 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
2334 | pub struct BorrowCheckResult<'gcx> { | |
2335 | pub closure_requirements: Option<ClosureRegionRequirements<'gcx>>, | |
2336 | pub used_mut_upvars: SmallVec<[Field; 8]>, | |
2337 | } | |
2338 | ||
ff7c6d11 XL |
2339 | /// After we borrow check a closure, we are left with various |
2340 | /// requirements that we have inferred between the free regions that | |
2341 | /// appear in the closure's signature or on its field types. These | |
2342 | /// requirements are then verified and proved by the closure's | |
2343 | /// creating function. This struct encodes those requirements. | |
2344 | /// | |
2345 | /// The requirements are listed as being between various | |
2346 | /// `RegionVid`. The 0th region refers to `'static`; subsequent region | |
2347 | /// vids refer to the free regions that appear in the closure (or | |
2348 | /// generator's) type, in order of appearance. (This numbering is | |
2349 | /// actually defined by the `UniversalRegions` struct in the NLL | |
2350 | /// region checker. See for example | |
2351 | /// `UniversalRegions::closure_mapping`.) Note that we treat the free | |
2352 | /// regions in the closure's type "as if" they were erased, so their | |
2353 | /// precise identity is not important, only their position. | |
2354 | /// | |
2355 | /// Example: If type check produces a closure with the closure substs: | |
2356 | /// | |
2357 | /// ```text | |
2358 | /// ClosureSubsts = [ | |
2359 | /// i8, // the "closure kind" | |
2360 | /// for<'x> fn(&'a &'x u32) -> &'x u32, // the "closure signature" | |
2361 | /// &'a String, // some upvar | |
2362 | /// ] | |
2363 | /// ``` | |
2364 | /// | |
2365 | /// here, there is one unique free region (`'a`) but it appears | |
0531ce1d | 2366 | /// twice. We would "renumber" each occurrence to a unique vid, as follows: |
ff7c6d11 XL |
2367 | /// |
2368 | /// ```text | |
2369 | /// ClosureSubsts = [ | |
2370 | /// i8, // the "closure kind" | |
2371 | /// for<'x> fn(&'1 &'x u32) -> &'x u32, // the "closure signature" | |
2372 | /// &'2 String, // some upvar | |
2373 | /// ] | |
2374 | /// ``` | |
2375 | /// | |
2376 | /// Now the code might impose a requirement like `'1: '2`. When an | |
2377 | /// instance of the closure is created, the corresponding free regions | |
2378 | /// can be extracted from its type and constrained to have the given | |
2379 | /// outlives relationship. | |
2380 | /// | |
2381 | /// In some cases, we have to record outlives requirements between | |
2382 | /// types and regions as well. In that case, if those types include | |
2383 | /// any regions, those regions are recorded as `ReClosureBound` | |
2384 | /// instances assigned one of these same indices. Those regions will | |
2385 | /// be substituted away by the creator. We use `ReClosureBound` in | |
2386 | /// that case because the regions must be allocated in the global | |
2387 | /// TyCtxt, and hence we cannot use `ReVar` (which is what we use | |
2388 | /// internally within the rest of the NLL code). | |
2389 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
2390 | pub struct ClosureRegionRequirements<'gcx> { | |
2391 | /// The number of external regions defined on the closure. In our | |
2392 | /// example above, it would be 3 -- one for `'static`, then `'1` | |
2393 | /// and `'2`. This is just used for a sanity check later on, to | |
2394 | /// make sure that the number of regions we see at the callsite | |
2395 | /// matches. | |
2396 | pub num_external_vids: usize, | |
2397 | ||
2398 | /// Requirements between the various free regions defined in | |
2399 | /// indices. | |
2400 | pub outlives_requirements: Vec<ClosureOutlivesRequirement<'gcx>>, | |
2401 | } | |
2402 | ||
2403 | /// Indicates an outlives constraint between a type or between two | |
2404 | /// free-regions declared on the closure. | |
2405 | #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] | |
2406 | pub struct ClosureOutlivesRequirement<'tcx> { | |
2407 | // This region or type ... | |
2408 | pub subject: ClosureOutlivesSubject<'tcx>, | |
2409 | ||
2410 | // .. must outlive this one. | |
2411 | pub outlived_free_region: ty::RegionVid, | |
2412 | ||
2413 | // If not, report an error here. | |
2414 | pub blame_span: Span, | |
2415 | } | |
2416 | ||
2417 | /// The subject of a ClosureOutlivesRequirement -- that is, the thing | |
2418 | /// that must outlive some region. | |
2419 | #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] | |
2420 | pub enum ClosureOutlivesSubject<'tcx> { | |
2421 | /// Subject is a type, typically a type parameter, but could also | |
2422 | /// be a projection. Indicates a requirement like `T: 'a` being | |
2423 | /// passed to the caller, where the type here is `T`. | |
2424 | /// | |
2425 | /// The type here is guaranteed not to contain any free regions at | |
2426 | /// present. | |
2427 | Ty(Ty<'tcx>), | |
2428 | ||
2429 | /// Subject is a free region from the closure. Indicates a requirement | |
2430 | /// like `'a: 'b` being passed to the caller; the region here is `'a`. | |
2431 | Region(ty::RegionVid), | |
2432 | } | |
2433 | ||
8bb4bdeb XL |
2434 | /* |
2435 | * TypeFoldable implementations for MIR types | |
2436 | */ | |
2437 | ||
0531ce1d XL |
2438 | CloneTypeFoldableAndLiftImpls! { |
2439 | Mutability, | |
2440 | SourceInfo, | |
2441 | UpvarDecl, | |
2442 | ValidationOp, | |
94b46f34 XL |
2443 | SourceScope, |
2444 | SourceScopeData, | |
2445 | SourceScopeLocalData, | |
8bb4bdeb XL |
2446 | } |
2447 | ||
0531ce1d XL |
2448 | BraceStructTypeFoldableImpl! { |
2449 | impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { | |
2450 | basic_blocks, | |
94b46f34 XL |
2451 | source_scopes, |
2452 | source_scope_local_data, | |
0531ce1d XL |
2453 | promoted, |
2454 | yield_ty, | |
2455 | generator_drop, | |
2456 | generator_layout, | |
2457 | local_decls, | |
2458 | arg_count, | |
2459 | upvar_decls, | |
2460 | spread_arg, | |
2461 | span, | |
2462 | cache, | |
ea8adc8c XL |
2463 | } |
2464 | } | |
2465 | ||
0531ce1d XL |
2466 | BraceStructTypeFoldableImpl! { |
2467 | impl<'tcx> TypeFoldable<'tcx> for GeneratorLayout<'tcx> { | |
2468 | fields | |
8bb4bdeb XL |
2469 | } |
2470 | } | |
2471 | ||
0531ce1d XL |
2472 | BraceStructTypeFoldableImpl! { |
2473 | impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> { | |
2474 | mutability, | |
2475 | is_user_variable, | |
2476 | internal, | |
2477 | ty, | |
2478 | name, | |
2479 | source_info, | |
94b46f34 | 2480 | visibility_scope, |
8bb4bdeb | 2481 | } |
0531ce1d | 2482 | } |
8bb4bdeb | 2483 | |
0531ce1d XL |
2484 | BraceStructTypeFoldableImpl! { |
2485 | impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> { | |
2486 | statements, | |
2487 | terminator, | |
2488 | is_cleanup, | |
8bb4bdeb XL |
2489 | } |
2490 | } | |
2491 | ||
0531ce1d XL |
2492 | BraceStructTypeFoldableImpl! { |
2493 | impl<'tcx> TypeFoldable<'tcx> for ValidationOperand<'tcx, Place<'tcx>> { | |
2494 | place, ty, re, mutbl | |
3b2f2976 | 2495 | } |
0531ce1d | 2496 | } |
3b2f2976 | 2497 | |
0531ce1d XL |
2498 | BraceStructTypeFoldableImpl! { |
2499 | impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { | |
2500 | source_info, kind | |
3b2f2976 XL |
2501 | } |
2502 | } | |
2503 | ||
0531ce1d XL |
2504 | EnumTypeFoldableImpl! { |
2505 | impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> { | |
2506 | (StatementKind::Assign)(a, b), | |
94b46f34 | 2507 | (StatementKind::ReadForMatch)(place), |
0531ce1d XL |
2508 | (StatementKind::SetDiscriminant) { place, variant_index }, |
2509 | (StatementKind::StorageLive)(a), | |
2510 | (StatementKind::StorageDead)(a), | |
2511 | (StatementKind::InlineAsm) { asm, outputs, inputs }, | |
2512 | (StatementKind::Validate)(a, b), | |
2513 | (StatementKind::EndRegion)(a), | |
2514 | (StatementKind::UserAssertTy)(a, b), | |
2515 | (StatementKind::Nop), | |
8bb4bdeb | 2516 | } |
0531ce1d | 2517 | } |
8bb4bdeb | 2518 | |
0531ce1d XL |
2519 | EnumTypeFoldableImpl! { |
2520 | impl<'tcx, T> TypeFoldable<'tcx> for ClearCrossCrate<T> { | |
2521 | (ClearCrossCrate::Clear), | |
2522 | (ClearCrossCrate::Set)(a), | |
2523 | } where T: TypeFoldable<'tcx> | |
8bb4bdeb XL |
2524 | } |
2525 | ||
2526 | impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { | |
2527 | fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { | |
2528 | use mir::TerminatorKind::*; | |
2529 | ||
2530 | let kind = match self.kind { | |
2531 | Goto { target } => Goto { target: target }, | |
94b46f34 XL |
2532 | SwitchInt { |
2533 | ref discr, | |
2534 | switch_ty, | |
2535 | ref values, | |
2536 | ref targets, | |
2537 | } => SwitchInt { | |
8bb4bdeb XL |
2538 | discr: discr.fold_with(folder), |
2539 | switch_ty: switch_ty.fold_with(folder), | |
2540 | values: values.clone(), | |
94b46f34 | 2541 | targets: targets.clone(), |
8bb4bdeb | 2542 | }, |
94b46f34 XL |
2543 | Drop { |
2544 | ref location, | |
2545 | target, | |
2546 | unwind, | |
2547 | } => Drop { | |
8bb4bdeb | 2548 | location: location.fold_with(folder), |
041b39d2 XL |
2549 | target, |
2550 | unwind, | |
8bb4bdeb | 2551 | }, |
94b46f34 XL |
2552 | DropAndReplace { |
2553 | ref location, | |
2554 | ref value, | |
2555 | target, | |
2556 | unwind, | |
2557 | } => DropAndReplace { | |
8bb4bdeb XL |
2558 | location: location.fold_with(folder), |
2559 | value: value.fold_with(folder), | |
041b39d2 XL |
2560 | target, |
2561 | unwind, | |
8bb4bdeb | 2562 | }, |
94b46f34 XL |
2563 | Yield { |
2564 | ref value, | |
2565 | resume, | |
2566 | drop, | |
2567 | } => Yield { | |
ea8adc8c XL |
2568 | value: value.fold_with(folder), |
2569 | resume: resume, | |
2570 | drop: drop, | |
2571 | }, | |
94b46f34 XL |
2572 | Call { |
2573 | ref func, | |
2574 | ref args, | |
2575 | ref destination, | |
2576 | cleanup, | |
2577 | } => { | |
2578 | let dest = destination | |
2579 | .as_ref() | |
2580 | .map(|&(ref loc, dest)| (loc.fold_with(folder), dest)); | |
8bb4bdeb XL |
2581 | |
2582 | Call { | |
2583 | func: func.fold_with(folder), | |
2584 | args: args.fold_with(folder), | |
2585 | destination: dest, | |
041b39d2 | 2586 | cleanup, |
8bb4bdeb | 2587 | } |
94b46f34 XL |
2588 | } |
2589 | Assert { | |
2590 | ref cond, | |
2591 | expected, | |
2592 | ref msg, | |
2593 | target, | |
2594 | cleanup, | |
2595 | } => { | |
83c7162d XL |
2596 | let msg = if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg { |
2597 | EvalErrorKind::BoundsCheck { | |
8bb4bdeb XL |
2598 | len: len.fold_with(folder), |
2599 | index: index.fold_with(folder), | |
2600 | } | |
2601 | } else { | |
2602 | msg.clone() | |
2603 | }; | |
2604 | Assert { | |
2605 | cond: cond.fold_with(folder), | |
041b39d2 XL |
2606 | expected, |
2607 | msg, | |
2608 | target, | |
2609 | cleanup, | |
8bb4bdeb | 2610 | } |
94b46f34 | 2611 | } |
ea8adc8c | 2612 | GeneratorDrop => GeneratorDrop, |
8bb4bdeb | 2613 | Resume => Resume, |
ff7c6d11 | 2614 | Abort => Abort, |
8bb4bdeb XL |
2615 | Return => Return, |
2616 | Unreachable => Unreachable, | |
94b46f34 XL |
2617 | FalseEdges { |
2618 | real_target, | |
2619 | ref imaginary_targets, | |
2620 | } => FalseEdges { | |
2621 | real_target, | |
2622 | imaginary_targets: imaginary_targets.clone(), | |
2623 | }, | |
2624 | FalseUnwind { | |
2625 | real_target, | |
2626 | unwind, | |
2627 | } => FalseUnwind { | |
2628 | real_target, | |
2629 | unwind, | |
2630 | }, | |
8bb4bdeb XL |
2631 | }; |
2632 | Terminator { | |
2633 | source_info: self.source_info, | |
041b39d2 | 2634 | kind, |
8bb4bdeb XL |
2635 | } |
2636 | } | |
2637 | ||
2638 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
2639 | use mir::TerminatorKind::*; | |
2640 | ||
2641 | match self.kind { | |
94b46f34 XL |
2642 | SwitchInt { |
2643 | ref discr, | |
2644 | switch_ty, | |
2645 | .. | |
2646 | } => discr.visit_with(visitor) || switch_ty.visit_with(visitor), | |
2647 | Drop { ref location, .. } => location.visit_with(visitor), | |
2648 | DropAndReplace { | |
2649 | ref location, | |
2650 | ref value, | |
2651 | .. | |
2652 | } => location.visit_with(visitor) || value.visit_with(visitor), | |
2653 | Yield { ref value, .. } => value.visit_with(visitor), | |
2654 | Call { | |
2655 | ref func, | |
2656 | ref args, | |
2657 | ref destination, | |
2658 | .. | |
2659 | } => { | |
8bb4bdeb XL |
2660 | let dest = if let Some((ref loc, _)) = *destination { |
2661 | loc.visit_with(visitor) | |
94b46f34 XL |
2662 | } else { |
2663 | false | |
2664 | }; | |
8bb4bdeb | 2665 | dest || func.visit_with(visitor) || args.visit_with(visitor) |
94b46f34 XL |
2666 | } |
2667 | Assert { | |
2668 | ref cond, ref msg, .. | |
2669 | } => { | |
8bb4bdeb | 2670 | if cond.visit_with(visitor) { |
83c7162d | 2671 | if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg { |
8bb4bdeb XL |
2672 | len.visit_with(visitor) || index.visit_with(visitor) |
2673 | } else { | |
2674 | false | |
2675 | } | |
2676 | } else { | |
2677 | false | |
2678 | } | |
94b46f34 XL |
2679 | } |
2680 | Goto { .. } | |
2681 | | Resume | |
2682 | | Abort | |
2683 | | Return | |
2684 | | GeneratorDrop | |
2685 | | Unreachable | |
2686 | | FalseEdges { .. } | |
2687 | | FalseUnwind { .. } => false, | |
8bb4bdeb XL |
2688 | } |
2689 | } | |
2690 | } | |
2691 | ||
ff7c6d11 | 2692 | impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { |
8bb4bdeb XL |
2693 | fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { |
2694 | match self { | |
ff7c6d11 | 2695 | &Place::Projection(ref p) => Place::Projection(p.fold_with(folder)), |
94b46f34 | 2696 | _ => self.clone(), |
8bb4bdeb XL |
2697 | } |
2698 | } | |
2699 | ||
2700 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
ff7c6d11 | 2701 | if let &Place::Projection(ref p) = self { |
8bb4bdeb XL |
2702 | p.visit_with(visitor) |
2703 | } else { | |
2704 | false | |
2705 | } | |
2706 | } | |
2707 | } | |
2708 | ||
2709 | impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { | |
2710 | fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { | |
2711 | use mir::Rvalue::*; | |
2712 | match *self { | |
2713 | Use(ref op) => Use(op.fold_with(folder)), | |
2714 | Repeat(ref op, len) => Repeat(op.fold_with(folder), len), | |
94b46f34 XL |
2715 | Ref(region, bk, ref place) => { |
2716 | Ref(region.fold_with(folder), bk, place.fold_with(folder)) | |
2717 | } | |
ff7c6d11 | 2718 | Len(ref place) => Len(place.fold_with(folder)), |
8bb4bdeb | 2719 | Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), |
94b46f34 XL |
2720 | BinaryOp(op, ref rhs, ref lhs) => { |
2721 | BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) | |
2722 | } | |
2723 | CheckedBinaryOp(op, ref rhs, ref lhs) => { | |
2724 | CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) | |
2725 | } | |
8bb4bdeb | 2726 | UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), |
ff7c6d11 | 2727 | Discriminant(ref place) => Discriminant(place.fold_with(folder)), |
7cac9316 | 2728 | NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), |
8bb4bdeb | 2729 | Aggregate(ref kind, ref fields) => { |
cc61c64b | 2730 | let kind = box match **kind { |
8bb4bdeb XL |
2731 | AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), |
2732 | AggregateKind::Tuple => AggregateKind::Tuple, | |
94b46f34 XL |
2733 | AggregateKind::Adt(def, v, substs, n) => { |
2734 | AggregateKind::Adt(def, v, substs.fold_with(folder), n) | |
2735 | } | |
2736 | AggregateKind::Closure(id, substs) => { | |
2737 | AggregateKind::Closure(id, substs.fold_with(folder)) | |
2738 | } | |
2739 | AggregateKind::Generator(id, substs, movablity) => { | |
2740 | AggregateKind::Generator(id, substs.fold_with(folder), movablity) | |
2741 | } | |
8bb4bdeb XL |
2742 | }; |
2743 | Aggregate(kind, fields.fold_with(folder)) | |
2744 | } | |
2745 | } | |
2746 | } | |
2747 | ||
2748 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
2749 | use mir::Rvalue::*; | |
2750 | match *self { | |
2751 | Use(ref op) => op.visit_with(visitor), | |
2752 | Repeat(ref op, _) => op.visit_with(visitor), | |
ff7c6d11 XL |
2753 | Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor), |
2754 | Len(ref place) => place.visit_with(visitor), | |
8bb4bdeb | 2755 | Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), |
94b46f34 XL |
2756 | BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => { |
2757 | rhs.visit_with(visitor) || lhs.visit_with(visitor) | |
2758 | } | |
8bb4bdeb | 2759 | UnaryOp(_, ref val) => val.visit_with(visitor), |
ff7c6d11 | 2760 | Discriminant(ref place) => place.visit_with(visitor), |
7cac9316 | 2761 | NullaryOp(_, ty) => ty.visit_with(visitor), |
8bb4bdeb | 2762 | Aggregate(ref kind, ref fields) => { |
cc61c64b | 2763 | (match **kind { |
8bb4bdeb XL |
2764 | AggregateKind::Array(ty) => ty.visit_with(visitor), |
2765 | AggregateKind::Tuple => false, | |
2766 | AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor), | |
ea8adc8c | 2767 | AggregateKind::Closure(_, substs) => substs.visit_with(visitor), |
94b46f34 | 2768 | AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor), |
8bb4bdeb XL |
2769 | }) || fields.visit_with(visitor) |
2770 | } | |
2771 | } | |
2772 | } | |
2773 | } | |
2774 | ||
2775 | impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { | |
2776 | fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { | |
2777 | match *self { | |
ff7c6d11 XL |
2778 | Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)), |
2779 | Operand::Move(ref place) => Operand::Move(place.fold_with(folder)), | |
8bb4bdeb XL |
2780 | Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), |
2781 | } | |
2782 | } | |
2783 | ||
2784 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
2785 | match *self { | |
94b46f34 XL |
2786 | Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), |
2787 | Operand::Constant(ref c) => c.visit_with(visitor), | |
8bb4bdeb XL |
2788 | } |
2789 | } | |
2790 | } | |
2791 | ||
3b2f2976 | 2792 | impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T> |
94b46f34 XL |
2793 | where |
2794 | B: TypeFoldable<'tcx>, | |
2795 | V: TypeFoldable<'tcx>, | |
2796 | T: TypeFoldable<'tcx>, | |
8bb4bdeb XL |
2797 | { |
2798 | fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { | |
2799 | use mir::ProjectionElem::*; | |
2800 | ||
2801 | let base = self.base.fold_with(folder); | |
2802 | let elem = match self.elem { | |
2803 | Deref => Deref, | |
3b2f2976 | 2804 | Field(f, ref ty) => Field(f, ty.fold_with(folder)), |
8bb4bdeb | 2805 | Index(ref v) => Index(v.fold_with(folder)), |
94b46f34 | 2806 | ref elem => elem.clone(), |
8bb4bdeb XL |
2807 | }; |
2808 | ||
94b46f34 | 2809 | Projection { base, elem } |
8bb4bdeb XL |
2810 | } |
2811 | ||
2812 | fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { | |
2813 | use mir::ProjectionElem::*; | |
2814 | ||
94b46f34 XL |
2815 | self.base.visit_with(visitor) || match self.elem { |
2816 | Field(_, ref ty) => ty.visit_with(visitor), | |
2817 | Index(ref v) => v.visit_with(visitor), | |
2818 | _ => false, | |
2819 | } | |
8bb4bdeb XL |
2820 | } |
2821 | } | |
2822 | ||
0531ce1d XL |
2823 | impl<'tcx> TypeFoldable<'tcx> for Field { |
2824 | fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { | |
2825 | *self | |
2826 | } | |
2827 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { | |
2828 | false | |
2829 | } | |
2830 | } | |
2831 | ||
8bb4bdeb XL |
2832 | impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { |
2833 | fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { | |
2834 | Constant { | |
2835 | span: self.span.clone(), | |
2836 | ty: self.ty.fold_with(folder), | |
94b46f34 | 2837 | literal: self.literal.fold_with(folder), |
8bb4bdeb XL |
2838 | } |
2839 | } | |
2840 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
2841 | self.ty.visit_with(visitor) || self.literal.visit_with(visitor) | |
2842 | } | |
2843 | } | |
2844 | ||
2845 | impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> { | |
2846 | fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { | |
2847 | match *self { | |
ea8adc8c | 2848 | Literal::Value { value } => Literal::Value { |
94b46f34 | 2849 | value: value.fold_with(folder), |
8bb4bdeb | 2850 | }, |
94b46f34 | 2851 | Literal::Promoted { index } => Literal::Promoted { index }, |
8bb4bdeb XL |
2852 | } |
2853 | } | |
2854 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
2855 | match *self { | |
ea8adc8c | 2856 | Literal::Value { value } => value.visit_with(visitor), |
94b46f34 | 2857 | Literal::Promoted { .. } => false, |
8bb4bdeb XL |
2858 | } |
2859 | } | |
2860 | } |