]>
Commit | Line | Data |
---|---|---|
48663c56 XL |
1 | // ignore-tidy-filelength |
2 | ||
0531ce1d | 3 | //! MIR datatypes and passes. See the [rustc guide] for more info. |
ff7c6d11 | 4 | //! |
a1dfa0c6 | 5 | //! [rustc guide]: https://rust-lang.github.io/rustc-guide/mir/index.html |
7cac9316 | 6 | |
532ac7d7 | 7 | use crate::hir::def::{CtorKind, Namespace}; |
9fa01778 | 8 | use crate::hir::def_id::DefId; |
48663c56 | 9 | use crate::hir::{self, InlineAsm as HirInlineAsm}; |
416331ca | 10 | use crate::mir::interpret::{ConstValue, PanicInfo, Scalar}; |
9fa01778 | 11 | use crate::mir::visit::MirVisitable; |
416331ca XL |
12 | use crate::ty::adjustment::PointerCast; |
13 | use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; | |
14 | use crate::ty::layout::VariantIdx; | |
15 | use crate::ty::print::{FmtPrinter, Printer}; | |
16 | use crate::ty::subst::{Subst, SubstsRef}; | |
17 | use crate::ty::{ | |
18 | self, AdtDef, CanonicalUserTypeAnnotations, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt, | |
19 | UserTypeAnnotationIndex, | |
20 | }; | |
21 | use polonius_engine::Atom; | |
dc9dc135 | 22 | use rustc_data_structures::bit_set::BitMatrix; |
a1dfa0c6 | 23 | use rustc_data_structures::fx::FxHashSet; |
8faf50e0 XL |
24 | use rustc_data_structures::graph::dominators::{dominators, Dominators}; |
25 | use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; | |
94b46f34 | 26 | use rustc_data_structures::indexed_vec::{Idx, IndexVec}; |
94b46f34 | 27 | use rustc_data_structures::sync::Lrc; |
b7449926 | 28 | use rustc_data_structures::sync::MappedReadGuard; |
532ac7d7 | 29 | use rustc_macros::HashStable; |
416331ca | 30 | use rustc_serialize::{Encodable, Decodable}; |
b7449926 | 31 | use smallvec::SmallVec; |
94b46f34 | 32 | use std::borrow::Cow; |
416331ca | 33 | use std::fmt::{self, Debug, Display, Formatter, Write}; |
48663c56 | 34 | use std::iter::FusedIterator; |
9cc50fc6 | 35 | use std::ops::{Index, IndexMut}; |
94b46f34 | 36 | use std::slice; |
3157f602 | 37 | use std::vec::IntoIter; |
94b46f34 | 38 | use std::{iter, mem, option, u32}; |
dc9dc135 | 39 | use syntax::ast::Name; |
532ac7d7 | 40 | use syntax::symbol::{InternedString, Symbol}; |
0531ce1d | 41 | use syntax_pos::{Span, DUMMY_SP}; |
83c7162d | 42 | |
9fa01778 | 43 | pub use crate::mir::interpret::AssertMessage; |
3157f602 | 44 | |
c30ab7b3 | 45 | mod cache; |
ff7c6d11 XL |
46 | pub mod interpret; |
47 | pub mod mono; | |
94b46f34 XL |
48 | pub mod tcx; |
49 | pub mod traversal; | |
50 | pub mod visit; | |
3157f602 | 51 | |
041b39d2 XL |
52 | /// Types for locals |
53 | type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>; | |
54 | ||
55 | pub trait HasLocalDecls<'tcx> { | |
56 | fn local_decls(&self) -> &LocalDecls<'tcx>; | |
57 | } | |
58 | ||
59 | impl<'tcx> HasLocalDecls<'tcx> for LocalDecls<'tcx> { | |
60 | fn local_decls(&self) -> &LocalDecls<'tcx> { | |
61 | self | |
62 | } | |
63 | } | |
64 | ||
dc9dc135 | 65 | impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { |
041b39d2 XL |
66 | fn local_decls(&self) -> &LocalDecls<'tcx> { |
67 | &self.local_decls | |
68 | } | |
69 | } | |
70 | ||
a1dfa0c6 XL |
71 | /// The various "big phases" that MIR goes through. |
72 | /// | |
73 | /// Warning: ordering of variants is significant | |
74 | #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] | |
75 | pub enum MirPhase { | |
76 | Build = 0, | |
77 | Const = 1, | |
78 | Validated = 2, | |
79 | Optimized = 3, | |
80 | } | |
81 | ||
82 | impl MirPhase { | |
83 | /// Gets the index of the current MirPhase within the set of all MirPhases. | |
84 | pub fn phase_index(&self) -> usize { | |
85 | *self as usize | |
86 | } | |
87 | } | |
88 | ||
e9174d1e | 89 | /// Lowered representation of a single function. |
8bb4bdeb | 90 | #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] |
dc9dc135 | 91 | pub struct Body<'tcx> { |
92a42be0 SL |
92 | /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` |
93 | /// that indexes into this vector. | |
3157f602 | 94 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, |
e9174d1e | 95 | |
a1dfa0c6 XL |
96 | /// Records how far through the "desugaring and optimization" process this particular |
97 | /// MIR has traversed. This is particularly useful when inlining, since in that context | |
98 | /// we instantiate the promoted constants and add them to our promoted vector -- but those | |
99 | /// promoted items have already been optimized, whereas ours have not. This field allows | |
100 | /// us to see the difference and forego optimization on the inlined promoted items. | |
101 | pub phase: MirPhase, | |
102 | ||
94b46f34 XL |
103 | /// List of source scopes; these are referenced by statements |
104 | /// and used for debuginfo. Indexed by a `SourceScope`. | |
105 | pub source_scopes: IndexVec<SourceScope, SourceScopeData>, | |
54a0048b | 106 | |
94b46f34 | 107 | /// Crate-local information for each source scope, that can't (and |
ea8adc8c | 108 | /// needn't) be tracked across crates. |
94b46f34 | 109 | pub source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>, |
ea8adc8c | 110 | |
a7813a04 | 111 | /// Rvalues promoted from this function, such as borrows of constants. |
dc9dc135 | 112 | /// Each of them is the Body of a constant with the fn's type parameters |
c30ab7b3 | 113 | /// in scope, but a separate set of locals. |
dc9dc135 | 114 | pub promoted: IndexVec<Promoted, Body<'tcx>>, |
a7813a04 | 115 | |
9fa01778 | 116 | /// Yields type of the function, if it is a generator. |
ea8adc8c XL |
117 | pub yield_ty: Option<Ty<'tcx>>, |
118 | ||
119 | /// Generator drop glue | |
dc9dc135 | 120 | pub generator_drop: Option<Box<Body<'tcx>>>, |
ea8adc8c XL |
121 | |
122 | /// The layout of a generator. Produced by the state transformation. | |
123 | pub generator_layout: Option<GeneratorLayout<'tcx>>, | |
124 | ||
c30ab7b3 SL |
125 | /// Declarations of locals. |
126 | /// | |
127 | /// The first local is the return value pointer, followed by `arg_count` | |
128 | /// locals for the function arguments, followed by any user-declared | |
129 | /// variables and temporaries. | |
041b39d2 | 130 | pub local_decls: LocalDecls<'tcx>, |
92a42be0 | 131 | |
0731742a XL |
132 | /// User type annotations |
133 | pub user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, | |
134 | ||
c30ab7b3 SL |
135 | /// Number of arguments this function takes. |
136 | /// | |
137 | /// Starting at local 1, `arg_count` locals will be provided by the caller | |
138 | /// and can be assumed to be initialized. | |
139 | /// | |
140 | /// If this MIR was built for a constant, this will be 0. | |
141 | pub arg_count: usize, | |
7453a54e | 142 | |
c30ab7b3 SL |
143 | /// Mark an argument local (which must be a tuple) as getting passed as |
144 | /// its individual components at the LLVM level. | |
145 | /// | |
146 | /// This is used for the "rust-call" ABI. | |
147 | pub spread_arg: Option<Local>, | |
148 | ||
48663c56 XL |
149 | /// Names and capture modes of all the closure upvars, assuming |
150 | /// the first argument is either the closure or a reference to it. | |
151 | // NOTE(eddyb) This is *strictly* a temporary hack for codegen | |
152 | // debuginfo generation, and will be removed at some point. | |
153 | // Do **NOT** use it for anything else, upvar information should not be | |
154 | // in the MIR, please rely on local crate HIR or other side-channels. | |
155 | pub __upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>, | |
156 | ||
0731742a XL |
157 | /// Mark this MIR of a const context other than const functions as having converted a `&&` or |
158 | /// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop | |
159 | /// this conversion from happening and use short circuiting, we will cause the following code | |
160 | /// to change the value of `x`: `let mut x = 42; false && { x = 55; true };` | |
161 | /// | |
162 | /// List of places where control flow was destroyed. Used for error reporting. | |
163 | pub control_flow_destroyed: Vec<(Span, String)>, | |
164 | ||
7453a54e SL |
165 | /// A span representing this MIR, for error reporting |
166 | pub span: Span, | |
3157f602 XL |
167 | |
168 | /// A cache for various calculations | |
94b46f34 | 169 | cache: cache::Cache, |
e9174d1e SL |
170 | } |
171 | ||
dc9dc135 | 172 | impl<'tcx> Body<'tcx> { |
94b46f34 XL |
173 | pub fn new( |
174 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, | |
175 | source_scopes: IndexVec<SourceScope, SourceScopeData>, | |
176 | source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>, | |
dc9dc135 | 177 | promoted: IndexVec<Promoted, Body<'tcx>>, |
94b46f34 | 178 | yield_ty: Option<Ty<'tcx>>, |
0731742a XL |
179 | local_decls: LocalDecls<'tcx>, |
180 | user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, | |
94b46f34 | 181 | arg_count: usize, |
48663c56 | 182 | __upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>, |
94b46f34 | 183 | span: Span, |
0731742a | 184 | control_flow_destroyed: Vec<(Span, String)>, |
94b46f34 | 185 | ) -> Self { |
ff7c6d11 | 186 | // We need `arg_count` locals, and one for the return place |
94b46f34 XL |
187 | assert!( |
188 | local_decls.len() >= arg_count + 1, | |
189 | "expected at least {} locals, got {}", | |
190 | arg_count + 1, | |
191 | local_decls.len() | |
192 | ); | |
c30ab7b3 | 193 | |
dc9dc135 | 194 | Body { |
a1dfa0c6 | 195 | phase: MirPhase::Build, |
041b39d2 | 196 | basic_blocks, |
94b46f34 XL |
197 | source_scopes, |
198 | source_scope_local_data, | |
041b39d2 | 199 | promoted, |
ea8adc8c XL |
200 | yield_ty, |
201 | generator_drop: None, | |
202 | generator_layout: None, | |
041b39d2 | 203 | local_decls, |
0731742a | 204 | user_type_annotations, |
041b39d2 | 205 | arg_count, |
48663c56 | 206 | __upvar_debuginfo_codegen_only_do_not_use, |
c30ab7b3 | 207 | spread_arg: None, |
041b39d2 | 208 | span, |
94b46f34 | 209 | cache: cache::Cache::new(), |
0731742a | 210 | control_flow_destroyed, |
3157f602 XL |
211 | } |
212 | } | |
213 | ||
214 | #[inline] | |
215 | pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> { | |
216 | &self.basic_blocks | |
217 | } | |
218 | ||
219 | #[inline] | |
220 | pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { | |
221 | self.cache.invalidate(); | |
222 | &mut self.basic_blocks | |
e9174d1e SL |
223 | } |
224 | ||
ff7c6d11 | 225 | #[inline] |
94b46f34 XL |
226 | pub fn basic_blocks_and_local_decls_mut( |
227 | &mut self, | |
416331ca | 228 | ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) { |
ff7c6d11 XL |
229 | self.cache.invalidate(); |
230 | (&mut self.basic_blocks, &mut self.local_decls) | |
231 | } | |
232 | ||
3157f602 | 233 | #[inline] |
b7449926 | 234 | pub fn predecessors(&self) -> MappedReadGuard<'_, IndexVec<BasicBlock, Vec<BasicBlock>>> { |
3157f602 | 235 | self.cache.predecessors(self) |
e9174d1e SL |
236 | } |
237 | ||
3157f602 | 238 | #[inline] |
b7449926 XL |
239 | pub fn predecessors_for(&self, bb: BasicBlock) -> MappedReadGuard<'_, Vec<BasicBlock>> { |
240 | MappedReadGuard::map(self.predecessors(), |p| &p[bb]) | |
241 | } | |
242 | ||
243 | #[inline] | |
244 | pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ { | |
245 | let if_zero_locations = if loc.statement_index == 0 { | |
246 | let predecessor_blocks = self.predecessors_for(loc.block); | |
247 | let num_predecessor_blocks = predecessor_blocks.len(); | |
248 | Some( | |
249 | (0..num_predecessor_blocks) | |
250 | .map(move |i| predecessor_blocks[i]) | |
251 | .map(move |bb| self.terminator_loc(bb)), | |
252 | ) | |
253 | } else { | |
254 | None | |
255 | }; | |
256 | ||
257 | let if_not_zero_locations = if loc.statement_index == 0 { | |
258 | None | |
259 | } else { | |
416331ca | 260 | Some(Location { block: loc.block, statement_index: loc.statement_index - 1 }) |
b7449926 XL |
261 | }; |
262 | ||
416331ca | 263 | if_zero_locations.into_iter().flatten().chain(if_not_zero_locations) |
3157f602 XL |
264 | } |
265 | ||
266 | #[inline] | |
267 | pub fn dominators(&self) -> Dominators<BasicBlock> { | |
268 | dominators(self) | |
269 | } | |
270 | ||
c30ab7b3 SL |
271 | #[inline] |
272 | pub fn local_kind(&self, local: Local) -> LocalKind { | |
b7449926 | 273 | let index = local.as_usize(); |
c30ab7b3 | 274 | if index == 0 { |
94b46f34 XL |
275 | debug_assert!( |
276 | self.local_decls[local].mutability == Mutability::Mut, | |
277 | "return place should be mutable" | |
278 | ); | |
c30ab7b3 SL |
279 | |
280 | LocalKind::ReturnPointer | |
281 | } else if index < self.arg_count + 1 { | |
282 | LocalKind::Arg | |
283 | } else if self.local_decls[local].name.is_some() { | |
284 | LocalKind::Var | |
285 | } else { | |
c30ab7b3 SL |
286 | LocalKind::Temp |
287 | } | |
288 | } | |
289 | ||
290 | /// Returns an iterator over all temporaries. | |
291 | #[inline] | |
94b46f34 XL |
292 | pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { |
293 | (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { | |
c30ab7b3 | 294 | let local = Local::new(index); |
94b46f34 | 295 | if self.local_decls[local].is_user_variable.is_some() { |
c30ab7b3 | 296 | None |
cc61c64b XL |
297 | } else { |
298 | Some(local) | |
3157f602 | 299 | } |
c30ab7b3 SL |
300 | }) |
301 | } | |
302 | ||
303 | /// Returns an iterator over all user-declared locals. | |
304 | #[inline] | |
94b46f34 XL |
305 | pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { |
306 | (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { | |
c30ab7b3 | 307 | let local = Local::new(index); |
94b46f34 | 308 | if self.local_decls[local].is_user_variable.is_some() { |
c30ab7b3 | 309 | Some(local) |
cc61c64b XL |
310 | } else { |
311 | None | |
3157f602 | 312 | } |
c30ab7b3 | 313 | }) |
3157f602 XL |
314 | } |
315 | ||
a1dfa0c6 XL |
316 | /// Returns an iterator over all user-declared mutable locals. |
317 | #[inline] | |
318 | pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { | |
319 | (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { | |
320 | let local = Local::new(index); | |
321 | let decl = &self.local_decls[local]; | |
322 | if decl.is_user_variable.is_some() && decl.mutability == Mutability::Mut { | |
323 | Some(local) | |
324 | } else { | |
325 | None | |
326 | } | |
327 | }) | |
328 | } | |
329 | ||
83c7162d XL |
330 | /// Returns an iterator over all user-declared mutable arguments and locals. |
331 | #[inline] | |
94b46f34 | 332 | pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { |
83c7162d XL |
333 | (1..self.local_decls.len()).filter_map(move |index| { |
334 | let local = Local::new(index); | |
335 | let decl = &self.local_decls[local]; | |
94b46f34 XL |
336 | if (decl.is_user_variable.is_some() || index < self.arg_count + 1) |
337 | && decl.mutability == Mutability::Mut | |
83c7162d XL |
338 | { |
339 | Some(local) | |
340 | } else { | |
341 | None | |
342 | } | |
343 | }) | |
344 | } | |
345 | ||
c30ab7b3 SL |
346 | /// Returns an iterator over all function arguments. |
347 | #[inline] | |
94b46f34 | 348 | pub fn args_iter(&self) -> impl Iterator<Item = Local> { |
c30ab7b3 | 349 | let arg_count = self.arg_count; |
0731742a | 350 | (1..=arg_count).map(Local::new) |
e9174d1e | 351 | } |
9e0c209e | 352 | |
c30ab7b3 | 353 | /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all |
ff7c6d11 | 354 | /// locals that are neither arguments nor the return place). |
c30ab7b3 | 355 | #[inline] |
94b46f34 | 356 | pub fn vars_and_temps_iter(&self) -> impl Iterator<Item = Local> { |
c30ab7b3 SL |
357 | let arg_count = self.arg_count; |
358 | let local_count = self.local_decls.len(); | |
94b46f34 | 359 | (arg_count + 1..local_count).map(Local::new) |
9e0c209e SL |
360 | } |
361 | ||
362 | /// Changes a statement to a nop. This is both faster than deleting instructions and avoids | |
363 | /// invalidating statement indices in `Location`s. | |
364 | pub fn make_statement_nop(&mut self, location: Location) { | |
365 | let block = &mut self[location.block]; | |
366 | debug_assert!(location.statement_index < block.statements.len()); | |
367 | block.statements[location.statement_index].make_nop() | |
368 | } | |
ea8adc8c XL |
369 | |
370 | /// Returns the source info associated with `location`. | |
371 | pub fn source_info(&self, location: Location) -> &SourceInfo { | |
372 | let block = &self[location.block]; | |
373 | let stmts = &block.statements; | |
374 | let idx = location.statement_index; | |
abe05a73 | 375 | if idx < stmts.len() { |
ea8adc8c XL |
376 | &stmts[idx].source_info |
377 | } else { | |
0bf4aa26 | 378 | assert_eq!(idx, stmts.len()); |
ea8adc8c XL |
379 | &block.terminator().source_info |
380 | } | |
381 | } | |
abe05a73 | 382 | |
9fa01778 | 383 | /// Checks if `sub` is a sub scope of `sup` |
94b46f34 | 384 | pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool { |
0bf4aa26 | 385 | while sub != sup { |
94b46f34 XL |
386 | match self.source_scopes[sub].parent_scope { |
387 | None => return false, | |
388 | Some(p) => sub = p, | |
389 | } | |
390 | } | |
0bf4aa26 | 391 | true |
94b46f34 XL |
392 | } |
393 | ||
9fa01778 | 394 | /// Returns the return type, it always return first element from `local_decls` array |
abe05a73 | 395 | pub fn return_ty(&self) -> Ty<'tcx> { |
ff7c6d11 | 396 | self.local_decls[RETURN_PLACE].ty |
abe05a73 | 397 | } |
b7449926 | 398 | |
9fa01778 | 399 | /// Gets the location of the terminator for the given block |
b7449926 | 400 | pub fn terminator_loc(&self, bb: BasicBlock) -> Location { |
416331ca | 401 | Location { block: bb, statement_index: self[bb].statements.len() } |
b7449926 | 402 | } |
ea8adc8c XL |
403 | } |
404 | ||
532ac7d7 | 405 | #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
ea8adc8c XL |
406 | pub enum Safety { |
407 | Safe, | |
408 | /// Unsafe because of a PushUnsafeBlock | |
409 | BuiltinUnsafe, | |
410 | /// Unsafe because of an unsafe fn | |
411 | FnUnsafe, | |
412 | /// Unsafe because of an `unsafe` block | |
532ac7d7 | 413 | ExplicitUnsafe(hir::HirId), |
e9174d1e SL |
414 | } |
415 | ||
dc9dc135 | 416 | impl_stable_hash_for!(struct Body<'tcx> { |
a1dfa0c6 | 417 | phase, |
cc61c64b | 418 | basic_blocks, |
94b46f34 XL |
419 | source_scopes, |
420 | source_scope_local_data, | |
cc61c64b | 421 | promoted, |
ea8adc8c XL |
422 | yield_ty, |
423 | generator_drop, | |
424 | generator_layout, | |
cc61c64b | 425 | local_decls, |
0731742a | 426 | user_type_annotations, |
cc61c64b | 427 | arg_count, |
48663c56 | 428 | __upvar_debuginfo_codegen_only_do_not_use, |
cc61c64b | 429 | spread_arg, |
0731742a | 430 | control_flow_destroyed, |
cc61c64b XL |
431 | span, |
432 | cache | |
433 | }); | |
434 | ||
dc9dc135 | 435 | impl<'tcx> Index<BasicBlock> for Body<'tcx> { |
9cc50fc6 SL |
436 | type Output = BasicBlockData<'tcx>; |
437 | ||
438 | #[inline] | |
439 | fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { | |
3157f602 | 440 | &self.basic_blocks()[index] |
9cc50fc6 SL |
441 | } |
442 | } | |
443 | ||
dc9dc135 | 444 | impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> { |
9cc50fc6 SL |
445 | #[inline] |
446 | fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { | |
3157f602 | 447 | &mut self.basic_blocks_mut()[index] |
9cc50fc6 SL |
448 | } |
449 | } | |
450 | ||
532ac7d7 | 451 | #[derive(Copy, Clone, Debug, HashStable)] |
ff7c6d11 | 452 | pub enum ClearCrossCrate<T> { |
ea8adc8c | 453 | Clear, |
94b46f34 | 454 | Set(T), |
ea8adc8c XL |
455 | } |
456 | ||
8faf50e0 XL |
457 | impl<T> ClearCrossCrate<T> { |
458 | pub fn assert_crate_local(self) -> T { | |
459 | match self { | |
460 | ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), | |
461 | ClearCrossCrate::Set(v) => v, | |
462 | } | |
463 | } | |
464 | } | |
465 | ||
416331ca XL |
466 | impl<T: Encodable> rustc_serialize::UseSpecializedEncodable for ClearCrossCrate<T> {} |
467 | impl<T: Decodable> rustc_serialize::UseSpecializedDecodable for ClearCrossCrate<T> {} | |
ea8adc8c | 468 | |
3157f602 XL |
469 | /// Grouped information about the source code origin of a MIR entity. |
470 | /// Intended to be inspected by diagnostics and debuginfo. | |
471 | /// Most passes can work with it as a whole, within a single function. | |
532ac7d7 | 472 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, HashStable)] |
3157f602 XL |
473 | pub struct SourceInfo { |
474 | /// Source span for the AST pertaining to this MIR entity. | |
475 | pub span: Span, | |
476 | ||
94b46f34 XL |
477 | /// The source scope, keeping track of which bindings can be |
478 | /// seen by debuginfo, active lint levels, `unsafe {...}`, etc. | |
479 | pub scope: SourceScope, | |
3157f602 XL |
480 | } |
481 | ||
e9174d1e SL |
482 | /////////////////////////////////////////////////////////////////////////// |
483 | // Mutability and borrow kinds | |
484 | ||
532ac7d7 | 485 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] |
e9174d1e SL |
486 | pub enum Mutability { |
487 | Mut, | |
488 | Not, | |
489 | } | |
490 | ||
94b46f34 XL |
491 | impl From<Mutability> for hir::Mutability { |
492 | fn from(m: Mutability) -> Self { | |
493 | match m { | |
494 | Mutability::Mut => hir::MutMutable, | |
495 | Mutability::Not => hir::MutImmutable, | |
496 | } | |
497 | } | |
498 | } | |
499 | ||
416331ca XL |
500 | #[derive( |
501 | Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, HashStable, | |
502 | )] | |
e9174d1e SL |
503 | pub enum BorrowKind { |
504 | /// Data must be immutable and is aliasable. | |
505 | Shared, | |
506 | ||
0bf4aa26 XL |
507 | /// The immediately borrowed place must be immutable, but projections from |
508 | /// it don't need to be. For example, a shallow borrow of `a.b` doesn't | |
509 | /// conflict with a mutable borrow of `a.b.c`. | |
510 | /// | |
511 | /// This is used when lowering matches: when matching on a place we want to | |
512 | /// ensure that place have the same value from the start of the match until | |
513 | /// an arm is selected. This prevents this code from compiling: | |
514 | /// | |
515 | /// let mut x = &Some(0); | |
516 | /// match *x { | |
517 | /// None => (), | |
518 | /// Some(_) if { x = &None; false } => (), | |
519 | /// Some(_) => (), | |
520 | /// } | |
521 | /// | |
522 | /// This can't be a shared borrow because mutably borrowing (*x as Some).0 | |
523 | /// should not prevent `if let None = x { ... }`, for example, because the | |
524 | /// mutating `(*x as Some).0` can't affect the discriminant of `x`. | |
525 | /// We can also report errors with this kind of borrow differently. | |
526 | Shallow, | |
527 | ||
9fa01778 | 528 | /// Data must be immutable but not aliasable. This kind of borrow |
e9174d1e | 529 | /// cannot currently be expressed by the user and is used only in |
b7449926 XL |
530 | /// implicit closure bindings. It is needed when the closure is |
531 | /// borrowing or mutating a mutable referent, e.g.: | |
e9174d1e | 532 | /// |
a1dfa0c6 XL |
533 | /// let x: &mut isize = ...; |
534 | /// let y = || *x += 5; | |
e9174d1e SL |
535 | /// |
536 | /// If we were to try to translate this closure into a more explicit | |
537 | /// form, we'd encounter an error with the code as written: | |
538 | /// | |
a1dfa0c6 XL |
539 | /// struct Env { x: & &mut isize } |
540 | /// let x: &mut isize = ...; | |
541 | /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn | |
542 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
e9174d1e | 543 | /// |
b7449926 | 544 | /// This is then illegal because you cannot mutate an `&mut` found |
e9174d1e SL |
545 | /// in an aliasable location. To solve, you'd have to translate with |
546 | /// an `&mut` borrow: | |
547 | /// | |
a1dfa0c6 XL |
548 | /// struct Env { x: & &mut isize } |
549 | /// let x: &mut isize = ...; | |
550 | /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x | |
551 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
e9174d1e SL |
552 | /// |
553 | /// Now the assignment to `**env.x` is legal, but creating a | |
554 | /// mutable pointer to `x` is not because `x` is not mutable. We | |
555 | /// could fix this by declaring `x` as `let mut x`. This is ok in | |
556 | /// user code, if awkward, but extra weird for closures, since the | |
557 | /// borrow is hidden. | |
558 | /// | |
559 | /// So we introduce a "unique imm" borrow -- the referent is | |
560 | /// immutable, but not aliasable. This solves the problem. For | |
561 | /// simplicity, we don't give users the way to express this | |
562 | /// borrow, it's just used when translating closures. | |
563 | Unique, | |
564 | ||
565 | /// Data is mutable and not aliasable. | |
2c00a5a8 | 566 | Mut { |
9fa01778 XL |
567 | /// `true` if this borrow arose from method-call auto-ref |
568 | /// (i.e., `adjustment::Adjust::Borrow`). | |
94b46f34 XL |
569 | allow_two_phase_borrow: bool, |
570 | }, | |
2c00a5a8 XL |
571 | } |
572 | ||
573 | impl BorrowKind { | |
574 | pub fn allows_two_phase_borrow(&self) -> bool { | |
575 | match *self { | |
0bf4aa26 XL |
576 | BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, |
577 | BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, | |
2c00a5a8 XL |
578 | } |
579 | } | |
e9174d1e SL |
580 | } |
581 | ||
582 | /////////////////////////////////////////////////////////////////////////// | |
583 | // Variables and temps | |
584 | ||
b7449926 XL |
585 | newtype_index! { |
586 | pub struct Local { | |
532ac7d7 | 587 | derive [HashStable] |
abe05a73 | 588 | DEBUG_FORMAT = "_{}", |
ff7c6d11 | 589 | const RETURN_PLACE = 0, |
b7449926 XL |
590 | } |
591 | } | |
54a0048b | 592 | |
416331ca XL |
593 | impl Atom for Local { |
594 | fn index(self) -> usize { | |
595 | Idx::index(self) | |
596 | } | |
597 | } | |
598 | ||
dc9dc135 | 599 | /// Classifies locals into categories. See `Body::local_kind`. |
532ac7d7 | 600 | #[derive(PartialEq, Eq, Debug, HashStable)] |
c30ab7b3 SL |
601 | pub enum LocalKind { |
602 | /// User-declared variable binding | |
603 | Var, | |
604 | /// Compiler-introduced temporary | |
605 | Temp, | |
606 | /// Function argument | |
607 | Arg, | |
608 | /// Location of function's return value | |
609 | ReturnPointer, | |
e9174d1e SL |
610 | } |
611 | ||
8faf50e0 XL |
612 | #[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] |
613 | pub struct VarBindingForm<'tcx> { | |
94b46f34 XL |
614 | /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? |
615 | pub binding_mode: ty::BindingMode, | |
616 | /// If an explicit type was provided for this variable binding, | |
617 | /// this holds the source Span of that type. | |
618 | /// | |
9fa01778 | 619 | /// NOTE: if you want to change this to a `HirId`, be wary that |
94b46f34 XL |
620 | /// doing so breaks incremental compilation (as of this writing), |
621 | /// while a `Span` does not cause our tests to fail. | |
622 | pub opt_ty_info: Option<Span>, | |
8faf50e0 XL |
623 | /// Place of the RHS of the =, or the subject of the `match` where this |
624 | /// variable is initialized. None in the case of `let PATTERN;`. | |
625 | /// Some((None, ..)) in the case of and `let [mut] x = ...` because | |
626 | /// (a) the right-hand side isn't evaluated as a place expression. | |
627 | /// (b) it gives a way to separate this case from the remaining cases | |
628 | /// for diagnostics. | |
629 | pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>, | |
b7449926 XL |
630 | /// Span of the pattern in which this variable was bound. |
631 | pub pat_span: Span, | |
94b46f34 XL |
632 | } |
633 | ||
8faf50e0 XL |
634 | #[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] |
635 | pub enum BindingForm<'tcx> { | |
94b46f34 | 636 | /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. |
8faf50e0 | 637 | Var(VarBindingForm<'tcx>), |
94b46f34 | 638 | /// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit. |
0bf4aa26 | 639 | ImplicitSelf(ImplicitSelfKind), |
8faf50e0 XL |
640 | /// Reference used in a guard expression to ensure immutability. |
641 | RefForGuard, | |
94b46f34 XL |
642 | } |
643 | ||
0bf4aa26 XL |
644 | /// Represents what type of implicit self a function has, if any. |
645 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] | |
646 | pub enum ImplicitSelfKind { | |
647 | /// Represents a `fn x(self);`. | |
648 | Imm, | |
649 | /// Represents a `fn x(mut self);`. | |
650 | Mut, | |
651 | /// Represents a `fn x(&self);`. | |
652 | ImmRef, | |
653 | /// Represents a `fn x(&mut self);`. | |
654 | MutRef, | |
655 | /// Represents when a function does not have a self argument or | |
656 | /// when a function has a `self: X` argument. | |
416331ca | 657 | None, |
0bf4aa26 XL |
658 | } |
659 | ||
8faf50e0 | 660 | CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } |
94b46f34 | 661 | |
8faf50e0 XL |
662 | impl_stable_hash_for!(struct self::VarBindingForm<'tcx> { |
663 | binding_mode, | |
664 | opt_ty_info, | |
b7449926 XL |
665 | opt_match_place, |
666 | pat_span | |
8faf50e0 | 667 | }); |
94b46f34 | 668 | |
0bf4aa26 XL |
669 | impl_stable_hash_for!(enum self::ImplicitSelfKind { |
670 | Imm, | |
671 | Mut, | |
672 | ImmRef, | |
673 | MutRef, | |
674 | None | |
675 | }); | |
676 | ||
a1dfa0c6 XL |
677 | impl_stable_hash_for!(enum self::MirPhase { |
678 | Build, | |
679 | Const, | |
680 | Validated, | |
681 | Optimized, | |
682 | }); | |
683 | ||
8faf50e0 | 684 | mod binding_form_impl { |
9fa01778 | 685 | use crate::ich::StableHashingContext; |
b7449926 | 686 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; |
8faf50e0 XL |
687 | |
688 | impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> { | |
b7449926 XL |
689 | fn hash_stable<W: StableHasherResult>( |
690 | &self, | |
691 | hcx: &mut StableHashingContext<'a>, | |
692 | hasher: &mut StableHasher<W>, | |
693 | ) { | |
8faf50e0 XL |
694 | use super::BindingForm::*; |
695 | ::std::mem::discriminant(self).hash_stable(hcx, hasher); | |
696 | ||
697 | match self { | |
698 | Var(binding) => binding.hash_stable(hcx, hasher), | |
0bf4aa26 | 699 | ImplicitSelf(kind) => kind.hash_stable(hcx, hasher), |
8faf50e0 XL |
700 | RefForGuard => (), |
701 | } | |
702 | } | |
703 | } | |
704 | } | |
94b46f34 | 705 | |
0bf4aa26 XL |
706 | /// `BlockTailInfo` is attached to the `LocalDecl` for temporaries |
707 | /// created during evaluation of expressions in a block tail | |
708 | /// expression; that is, a block like `{ STMT_1; STMT_2; EXPR }`. | |
709 | /// | |
710 | /// It is used to improve diagnostics when such temporaries are | |
0731742a | 711 | /// involved in borrow_check errors, e.g., explanations of where the |
0bf4aa26 XL |
712 | /// temporaries come from, when their destructors are run, and/or how |
713 | /// one might revise the code to satisfy the borrow checker's rules. | |
714 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
715 | pub struct BlockTailInfo { | |
716 | /// If `true`, then the value resulting from evaluating this tail | |
717 | /// expression is ignored by the block's expression context. | |
718 | /// | |
719 | /// Examples include `{ ...; tail };` and `let _ = { ...; tail };` | |
0731742a | 720 | /// but not e.g., `let _x = { ...; tail };` |
0bf4aa26 XL |
721 | pub tail_result_is_ignored: bool, |
722 | } | |
723 | ||
724 | impl_stable_hash_for!(struct BlockTailInfo { tail_result_is_ignored }); | |
725 | ||
c30ab7b3 | 726 | /// A MIR local. |
7453a54e | 727 | /// |
c30ab7b3 | 728 | /// This can be a binding declared by the user, a temporary inserted by the compiler, a function |
ff7c6d11 | 729 | /// argument, or the return place. |
532ac7d7 | 730 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
c30ab7b3 SL |
731 | pub struct LocalDecl<'tcx> { |
732 | /// `let mut x` vs `let x`. | |
733 | /// | |
ff7c6d11 | 734 | /// Temporaries and the return place are always mutable. |
c30ab7b3 SL |
735 | pub mutability: Mutability, |
736 | ||
94b46f34 XL |
737 | /// Some(binding_mode) if this corresponds to a user-declared local variable. |
738 | /// | |
739 | /// This is solely used for local diagnostics when generating | |
740 | /// warnings/errors when compiling the current crate, and | |
741 | /// therefore it need not be visible across crates. pnkfelix | |
742 | /// currently hypothesized we *need* to wrap this in a | |
743 | /// `ClearCrossCrate` as long as it carries as `HirId`. | |
8faf50e0 | 744 | pub is_user_variable: Option<ClearCrossCrate<BindingForm<'tcx>>>, |
cc61c64b | 745 | |
9fa01778 | 746 | /// `true` if this is an internal local. |
ea8adc8c XL |
747 | /// |
748 | /// These locals are not based on types in the source code and are only used | |
749 | /// for a few desugarings at the moment. | |
750 | /// | |
751 | /// The generator transformation will sanity check the locals which are live | |
752 | /// across a suspension point against the type components of the generator | |
753 | /// which type checking knows are live across a suspension point. We need to | |
754 | /// flag drop flags to avoid triggering this check as they are introduced | |
755 | /// after typeck. | |
756 | /// | |
757 | /// Unsafety checking will also ignore dereferences of these locals, | |
758 | /// so they can be used for raw pointers only used in a desugaring. | |
759 | /// | |
760 | /// This should be sound because the drop flags are fully algebraic, and | |
761 | /// therefore don't affect the OIBIT or outlives properties of the | |
762 | /// generator. | |
763 | pub internal: bool, | |
764 | ||
0bf4aa26 XL |
765 | /// If this local is a temporary and `is_block_tail` is `Some`, |
766 | /// then it is a temporary created for evaluation of some | |
767 | /// subexpression of some block's tail expression (with no | |
768 | /// intervening statement context). | |
769 | pub is_block_tail: Option<BlockTailInfo>, | |
770 | ||
c30ab7b3 | 771 | /// Type of this local. |
b039eaaf | 772 | pub ty: Ty<'tcx>, |
54a0048b | 773 | |
b7449926 | 774 | /// If the user manually ascribed a type to this variable, |
0731742a | 775 | /// e.g., via `let x: T`, then we carry that type here. The MIR |
b7449926 XL |
776 | /// borrow checker needs this information since it can affect |
777 | /// region inference. | |
532ac7d7 | 778 | pub user_ty: UserTypeProjections, |
b7449926 | 779 | |
c30ab7b3 SL |
780 | /// Name of the local, used in debuginfo and pretty-printing. |
781 | /// | |
782 | /// Note that function arguments can also have this set to `Some(_)` | |
783 | /// to generate better debuginfo. | |
784 | pub name: Option<Name>, | |
a7813a04 | 785 | |
0731742a | 786 | /// The *syntactic* (i.e., not visibility) source scope the local is defined |
ea8adc8c XL |
787 | /// in. If the local was defined in a let-statement, this |
788 | /// is *within* the let-statement, rather than outside | |
789 | /// of it. | |
ff7c6d11 | 790 | /// |
94b46f34 XL |
791 | /// This is needed because the visibility source scope of locals within |
792 | /// a let-statement is weird. | |
ff7c6d11 XL |
793 | /// |
794 | /// The reason is that we want the local to be *within* the let-statement | |
795 | /// for lint purposes, but we want the local to be *after* the let-statement | |
796 | /// for names-in-scope purposes. | |
797 | /// | |
798 | /// That's it, if we have a let-statement like the one in this | |
799 | /// function: | |
800 | /// | |
801 | /// ``` | |
802 | /// fn foo(x: &str) { | |
803 | /// #[allow(unused_mut)] | |
804 | /// let mut x: u32 = { // <- one unused mut | |
805 | /// let mut y: u32 = x.parse().unwrap(); | |
806 | /// y + 2 | |
807 | /// }; | |
808 | /// drop(x); | |
809 | /// } | |
810 | /// ``` | |
811 | /// | |
812 | /// Then, from a lint point of view, the declaration of `x: u32` | |
813 | /// (and `y: u32`) are within the `#[allow(unused_mut)]` scope - the | |
814 | /// lint scopes are the same as the AST/HIR nesting. | |
815 | /// | |
816 | /// However, from a name lookup point of view, the scopes look more like | |
817 | /// as if the let-statements were `match` expressions: | |
818 | /// | |
819 | /// ``` | |
820 | /// fn foo(x: &str) { | |
821 | /// match { | |
822 | /// match x.parse().unwrap() { | |
823 | /// y => y + 2 | |
824 | /// } | |
825 | /// } { | |
826 | /// x => drop(x) | |
827 | /// }; | |
828 | /// } | |
829 | /// ``` | |
830 | /// | |
831 | /// We care about the name-lookup scopes for debuginfo - if the | |
832 | /// debuginfo instruction pointer is at the call to `x.parse()`, we | |
833 | /// want `x` to refer to `x: &str`, but if it is at the call to | |
834 | /// `drop(x)`, we want it to refer to `x: u32`. | |
835 | /// | |
836 | /// To allow both uses to work, we need to have more than a single scope | |
94b46f34 | 837 | /// for a local. We have the `source_info.scope` represent the |
ff7c6d11 | 838 | /// "syntactic" lint scope (with a variable being under its let |
94b46f34 | 839 | /// block) while the `visibility_scope` represents the "local variable" |
ff7c6d11 XL |
840 | /// scope (where the "rest" of a block is under all prior let-statements). |
841 | /// | |
842 | /// The end result looks like this: | |
843 | /// | |
844 | /// ```text | |
845 | /// ROOT SCOPE | |
846 | /// │{ argument x: &str } | |
847 | /// │ | |
b7449926 | 848 | /// │ │{ #[allow(unused_mut)] } // this is actually split into 2 scopes |
ff7c6d11 XL |
849 | /// │ │ // in practice because I'm lazy. |
850 | /// │ │ | |
94b46f34 | 851 | /// │ │← x.source_info.scope |
ff7c6d11 XL |
852 | /// │ │← `x.parse().unwrap()` |
853 | /// │ │ | |
94b46f34 | 854 | /// │ │ │← y.source_info.scope |
ff7c6d11 XL |
855 | /// │ │ |
856 | /// │ │ │{ let y: u32 } | |
857 | /// │ │ │ | |
94b46f34 | 858 | /// │ │ │← y.visibility_scope |
ff7c6d11 XL |
859 | /// │ │ │← `y + 2` |
860 | /// │ | |
861 | /// │ │{ let x: u32 } | |
94b46f34 | 862 | /// │ │← x.visibility_scope |
ff7c6d11 XL |
863 | /// │ │← `drop(x)` // this accesses `x: u32` |
864 | /// ``` | |
94b46f34 XL |
865 | pub source_info: SourceInfo, |
866 | ||
867 | /// Source scope within which the local is visible (for debuginfo) | |
868 | /// (see `source_info` for more details). | |
869 | pub visibility_scope: SourceScope, | |
c30ab7b3 SL |
870 | } |
871 | ||
872 | impl<'tcx> LocalDecl<'tcx> { | |
9fa01778 | 873 | /// Returns `true` only if local is a binding that can itself be |
94b46f34 XL |
874 | /// made mutable via the addition of the `mut` keyword, namely |
875 | /// something like the occurrences of `x` in: | |
876 | /// - `fn foo(x: Type) { ... }`, | |
877 | /// - `let x = ...`, | |
878 | /// - or `match ... { C(x) => ... }` | |
879 | pub fn can_be_made_mutable(&self) -> bool { | |
880 | match self.is_user_variable { | |
881 | Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { | |
882 | binding_mode: ty::BindingMode::BindByValue(_), | |
883 | opt_ty_info: _, | |
8faf50e0 | 884 | opt_match_place: _, |
b7449926 | 885 | pat_span: _, |
94b46f34 XL |
886 | }))) => true, |
887 | ||
416331ca | 888 | Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm))) => true, |
0bf4aa26 | 889 | |
94b46f34 XL |
890 | _ => false, |
891 | } | |
892 | } | |
893 | ||
9fa01778 | 894 | /// Returns `true` if local is definitely not a `ref ident` or |
94b46f34 XL |
895 | /// `ref mut ident` binding. (Such bindings cannot be made into |
896 | /// mutable bindings, but the inverse does not necessarily hold). | |
897 | pub fn is_nonref_binding(&self) -> bool { | |
898 | match self.is_user_variable { | |
899 | Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { | |
900 | binding_mode: ty::BindingMode::BindByValue(_), | |
901 | opt_ty_info: _, | |
8faf50e0 | 902 | opt_match_place: _, |
b7449926 | 903 | pat_span: _, |
94b46f34 XL |
904 | }))) => true, |
905 | ||
0bf4aa26 | 906 | Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true, |
94b46f34 XL |
907 | |
908 | _ => false, | |
909 | } | |
910 | } | |
911 | ||
dc9dc135 XL |
912 | /// Returns `true` if this is a reference to a variable bound in a `match` |
913 | /// expression that is used to access said variable for the guard of the | |
914 | /// match arm. | |
915 | pub fn is_ref_for_guard(&self) -> bool { | |
916 | match self.is_user_variable { | |
917 | Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true, | |
918 | _ => false, | |
919 | } | |
920 | } | |
921 | ||
922 | /// Returns `true` is the local is from a compiler desugaring, e.g., | |
923 | /// `__next` from a `for` loop. | |
924 | #[inline] | |
925 | pub fn from_compiler_desugaring(&self) -> bool { | |
416331ca | 926 | self.source_info.span.desugaring_kind().is_some() |
dc9dc135 XL |
927 | } |
928 | ||
9fa01778 | 929 | /// Creates a new `LocalDecl` for a temporary. |
c30ab7b3 | 930 | #[inline] |
cc61c64b | 931 | pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self { |
b7449926 XL |
932 | Self::new_local(ty, Mutability::Mut, false, span) |
933 | } | |
934 | ||
0bf4aa26 | 935 | /// Converts `self` into same `LocalDecl` except tagged as immutable. |
b7449926 | 936 | #[inline] |
0bf4aa26 XL |
937 | pub fn immutable(mut self) -> Self { |
938 | self.mutability = Mutability::Not; | |
939 | self | |
940 | } | |
941 | ||
942 | /// Converts `self` into same `LocalDecl` except tagged as internal temporary. | |
943 | #[inline] | |
944 | pub fn block_tail(mut self, info: BlockTailInfo) -> Self { | |
945 | assert!(self.is_block_tail.is_none()); | |
946 | self.is_block_tail = Some(info); | |
947 | self | |
ea8adc8c XL |
948 | } |
949 | ||
9fa01778 | 950 | /// Creates a new `LocalDecl` for a internal temporary. |
ea8adc8c XL |
951 | #[inline] |
952 | pub fn new_internal(ty: Ty<'tcx>, span: Span) -> Self { | |
b7449926 XL |
953 | Self::new_local(ty, Mutability::Mut, true, span) |
954 | } | |
955 | ||
956 | #[inline] | |
416331ca | 957 | fn new_local(ty: Ty<'tcx>, mutability: Mutability, internal: bool, span: Span) -> Self { |
ea8adc8c | 958 | LocalDecl { |
b7449926 | 959 | mutability, |
ea8adc8c | 960 | ty, |
0bf4aa26 | 961 | user_ty: UserTypeProjections::none(), |
ea8adc8c | 962 | name: None, |
416331ca | 963 | source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }, |
94b46f34 | 964 | visibility_scope: OUTERMOST_SOURCE_SCOPE, |
b7449926 | 965 | internal, |
94b46f34 | 966 | is_user_variable: None, |
0bf4aa26 | 967 | is_block_tail: None, |
c30ab7b3 SL |
968 | } |
969 | } | |
970 | ||
ff7c6d11 | 971 | /// Builds a `LocalDecl` for the return place. |
c30ab7b3 SL |
972 | /// |
973 | /// This must be inserted into the `local_decls` list as the first local. | |
974 | #[inline] | |
0bf4aa26 | 975 | pub fn new_return_place(return_ty: Ty<'_>, span: Span) -> LocalDecl<'_> { |
c30ab7b3 SL |
976 | LocalDecl { |
977 | mutability: Mutability::Mut, | |
978 | ty: return_ty, | |
0bf4aa26 | 979 | user_ty: UserTypeProjections::none(), |
416331ca | 980 | source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }, |
94b46f34 | 981 | visibility_scope: OUTERMOST_SOURCE_SCOPE, |
ea8adc8c | 982 | internal: false, |
0bf4aa26 | 983 | is_block_tail: None, |
94b46f34 XL |
984 | name: None, // FIXME maybe we do want some name here? |
985 | is_user_variable: None, | |
c30ab7b3 SL |
986 | } |
987 | } | |
a7813a04 XL |
988 | } |
989 | ||
990 | /// A closure capture, with its name and mode. | |
532ac7d7 | 991 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
48663c56 | 992 | pub struct UpvarDebuginfo { |
a7813a04 XL |
993 | pub debug_name: Name, |
994 | ||
995 | /// If true, the capture is behind a reference. | |
ff7c6d11 | 996 | pub by_ref: bool, |
e9174d1e SL |
997 | } |
998 | ||
e9174d1e SL |
999 | /////////////////////////////////////////////////////////////////////////// |
1000 | // BasicBlock | |
1001 | ||
b7449926 XL |
1002 | newtype_index! { |
1003 | pub struct BasicBlock { | |
532ac7d7 | 1004 | derive [HashStable] |
b7449926 XL |
1005 | DEBUG_FORMAT = "bb{}", |
1006 | const START_BLOCK = 0, | |
1007 | } | |
1008 | } | |
abe05a73 XL |
1009 | |
1010 | impl BasicBlock { | |
1011 | pub fn start_location(self) -> Location { | |
416331ca | 1012 | Location { block: self, statement_index: 0 } |
abe05a73 XL |
1013 | } |
1014 | } | |
e9174d1e SL |
1015 | |
1016 | /////////////////////////////////////////////////////////////////////////// | |
54a0048b | 1017 | // BasicBlockData and Terminator |
e9174d1e | 1018 | |
532ac7d7 | 1019 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
b039eaaf | 1020 | pub struct BasicBlockData<'tcx> { |
54a0048b | 1021 | /// List of statements in this block. |
b039eaaf | 1022 | pub statements: Vec<Statement<'tcx>>, |
54a0048b SL |
1023 | |
1024 | /// Terminator for this block. | |
1025 | /// | |
9fa01778 | 1026 | /// N.B., this should generally ONLY be `None` during construction. |
54a0048b SL |
1027 | /// Therefore, you should generally access it via the |
1028 | /// `terminator()` or `terminator_mut()` methods. The only | |
1029 | /// exception is that certain passes, such as `simplify_cfg`, swap | |
1030 | /// out the terminator temporarily with `None` while they continue | |
1031 | /// to recurse over the set of basic blocks. | |
9cc50fc6 | 1032 | pub terminator: Option<Terminator<'tcx>>, |
54a0048b SL |
1033 | |
1034 | /// If true, this block lies on an unwind path. This is used | |
94b46f34 | 1035 | /// during codegen where distinct kinds of basic blocks may be |
54a0048b SL |
1036 | /// generated (particularly for MSVC cleanup). Unwind blocks must |
1037 | /// only branch to other unwind blocks. | |
9cc50fc6 | 1038 | pub is_cleanup: bool, |
e9174d1e SL |
1039 | } |
1040 | ||
532ac7d7 | 1041 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
54a0048b | 1042 | pub struct Terminator<'tcx> { |
3157f602 | 1043 | pub source_info: SourceInfo, |
94b46f34 | 1044 | pub kind: TerminatorKind<'tcx>, |
54a0048b SL |
1045 | } |
1046 | ||
532ac7d7 | 1047 | #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] |
54a0048b | 1048 | pub enum TerminatorKind<'tcx> { |
e9174d1e | 1049 | /// block should have one successor in the graph; we jump there |
94b46f34 | 1050 | Goto { target: BasicBlock }, |
e9174d1e | 1051 | |
92a42be0 SL |
1052 | /// operand evaluates to an integer; jump depending on its value |
1053 | /// to one of the targets, and otherwise fallback to `otherwise` | |
1054 | SwitchInt { | |
1055 | /// discriminant value being tested | |
8bb4bdeb | 1056 | discr: Operand<'tcx>, |
92a42be0 SL |
1057 | |
1058 | /// type of value being tested | |
1059 | switch_ty: Ty<'tcx>, | |
1060 | ||
1061 | /// Possible values. The locations to branch to in each case | |
1062 | /// are found in the corresponding indices from the `targets` vector. | |
0531ce1d | 1063 | values: Cow<'tcx, [u128]>, |
8bb4bdeb XL |
1064 | |
1065 | /// Possible branch sites. The last element of this vector is used | |
cc61c64b | 1066 | /// for the otherwise branch, so targets.len() == values.len() + 1 |
8bb4bdeb XL |
1067 | /// should hold. |
1068 | // This invariant is quite non-obvious and also could be improved. | |
1069 | // One way to make this invariant is to have something like this instead: | |
1070 | // | |
1071 | // branches: Vec<(ConstInt, BasicBlock)>, | |
1072 | // otherwise: Option<BasicBlock> // exhaustive if None | |
1073 | // | |
1074 | // However we’ve decided to keep this as-is until we figure a case | |
1075 | // where some other approach seems to be strictly better than other. | |
b039eaaf SL |
1076 | targets: Vec<BasicBlock>, |
1077 | }, | |
e9174d1e | 1078 | |
9cc50fc6 SL |
1079 | /// Indicates that the landing pad is finished and unwinding should |
1080 | /// continue. Emitted by build::scope::diverge_cleanup. | |
1081 | Resume, | |
e9174d1e | 1082 | |
ff7c6d11 XL |
1083 | /// Indicates that the landing pad is finished and that the process |
1084 | /// should abort. Used to prevent unwinding for foreign items. | |
1085 | Abort, | |
1086 | ||
1087 | /// Indicates a normal return. The return place should have | |
1088 | /// been filled in by now. This should occur at most once. | |
e9174d1e SL |
1089 | Return, |
1090 | ||
3157f602 XL |
1091 | /// Indicates a terminator that can never be reached. |
1092 | Unreachable, | |
1093 | ||
ff7c6d11 | 1094 | /// Drop the Place |
416331ca | 1095 | Drop { location: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, |
7453a54e | 1096 | |
ff7c6d11 | 1097 | /// Drop the Place and assign the new value over it. This ensures |
2c00a5a8 | 1098 | /// that the assignment to `P` occurs *even if* the destructor for |
b7449926 | 1099 | /// place unwinds. Its semantics are best explained by the |
abe05a73 XL |
1100 | /// elaboration: |
1101 | /// | |
1102 | /// ``` | |
1103 | /// BB0 { | |
2c00a5a8 | 1104 | /// DropAndReplace(P <- V, goto BB1, unwind BB2) |
abe05a73 XL |
1105 | /// } |
1106 | /// ``` | |
1107 | /// | |
1108 | /// becomes | |
1109 | /// | |
1110 | /// ``` | |
1111 | /// BB0 { | |
2c00a5a8 | 1112 | /// Drop(P, goto BB1, unwind BB2) |
abe05a73 XL |
1113 | /// } |
1114 | /// BB1 { | |
b7449926 | 1115 | /// // P is now uninitialized |
2c00a5a8 | 1116 | /// P <- V |
abe05a73 XL |
1117 | /// } |
1118 | /// BB2 { | |
b7449926 | 1119 | /// // P is now uninitialized -- its dtor panicked |
2c00a5a8 | 1120 | /// P <- V |
abe05a73 XL |
1121 | /// } |
1122 | /// ``` | |
3157f602 | 1123 | DropAndReplace { |
ff7c6d11 | 1124 | location: Place<'tcx>, |
3157f602 XL |
1125 | value: Operand<'tcx>, |
1126 | target: BasicBlock, | |
1127 | unwind: Option<BasicBlock>, | |
1128 | }, | |
1129 | ||
9cc50fc6 | 1130 | /// Block ends with a call of a converging function |
b039eaaf | 1131 | Call { |
9cc50fc6 SL |
1132 | /// The function that’s being called |
1133 | func: Operand<'tcx>, | |
abe05a73 XL |
1134 | /// Arguments the function is called with. |
1135 | /// These are owned by the callee, which is free to modify them. | |
1136 | /// This allows the memory occupied by "by-value" arguments to be | |
1137 | /// reused across function calls without duplicating the contents. | |
9cc50fc6 | 1138 | args: Vec<Operand<'tcx>>, |
7453a54e | 1139 | /// Destination for the return value. If some, the call is converging. |
ff7c6d11 | 1140 | destination: Option<(Place<'tcx>, BasicBlock)>, |
7453a54e | 1141 | /// Cleanups to be done if the call unwinds. |
94b46f34 | 1142 | cleanup: Option<BasicBlock>, |
0bf4aa26 XL |
1143 | /// Whether this is from a call in HIR, rather than from an overloaded |
1144 | /// operator. True for overloaded function call. | |
1145 | from_hir_call: bool, | |
b039eaaf | 1146 | }, |
3157f602 XL |
1147 | |
1148 | /// Jump to the target if the condition has the expected value, | |
1149 | /// otherwise panic with a message and a cleanup target. | |
1150 | Assert { | |
1151 | cond: Operand<'tcx>, | |
1152 | expected: bool, | |
1153 | msg: AssertMessage<'tcx>, | |
1154 | target: BasicBlock, | |
94b46f34 | 1155 | cleanup: Option<BasicBlock>, |
ea8adc8c XL |
1156 | }, |
1157 | ||
1158 | /// A suspend point | |
1159 | Yield { | |
1160 | /// The value to return | |
1161 | value: Operand<'tcx>, | |
1162 | /// Where to resume to | |
1163 | resume: BasicBlock, | |
1164 | /// Cleanup to be done if the generator is dropped at this suspend point | |
1165 | drop: Option<BasicBlock>, | |
1166 | }, | |
1167 | ||
1168 | /// Indicates the end of the dropping of a generator | |
1169 | GeneratorDrop, | |
abe05a73 | 1170 | |
2c00a5a8 XL |
1171 | /// A block where control flow only ever takes one real path, but borrowck |
1172 | /// needs to be more conservative. | |
abe05a73 | 1173 | FalseEdges { |
2c00a5a8 | 1174 | /// The target normal control flow will take |
abe05a73 | 1175 | real_target: BasicBlock, |
dc9dc135 XL |
1176 | /// A block control flow could conceptually jump to, but won't in |
1177 | /// practice | |
1178 | imaginary_target: BasicBlock, | |
2c00a5a8 XL |
1179 | }, |
1180 | /// A terminator for blocks that only take one path in reality, but where we | |
1181 | /// reserve the right to unwind in borrowck, even if it won't happen in practice. | |
1182 | /// This can arise in infinite loops with no function calls for example. | |
1183 | FalseUnwind { | |
1184 | /// The target normal control flow will take | |
1185 | real_target: BasicBlock, | |
1186 | /// The imaginary cleanup block link. This particular path will never be taken | |
1187 | /// in practice, but in order to avoid fragility we want to always | |
1188 | /// consider it in borrowck. We don't want to accept programs which | |
1189 | /// pass borrowck only when panic=abort or some assertions are disabled | |
1190 | /// due to release vs. debug mode builds. This needs to be an Option because | |
1191 | /// of the remove_noop_landing_pads and no_landing_pads passes | |
1192 | unwind: Option<BasicBlock>, | |
abe05a73 | 1193 | }, |
e9174d1e SL |
1194 | } |
1195 | ||
83c7162d XL |
1196 | pub type Successors<'a> = |
1197 | iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>; | |
1198 | pub type SuccessorsMut<'a> = | |
1199 | iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; | |
1200 | ||
b039eaaf | 1201 | impl<'tcx> Terminator<'tcx> { |
0bf4aa26 | 1202 | pub fn successors(&self) -> Successors<'_> { |
54a0048b SL |
1203 | self.kind.successors() |
1204 | } | |
1205 | ||
0bf4aa26 | 1206 | pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { |
54a0048b SL |
1207 | self.kind.successors_mut() |
1208 | } | |
ff7c6d11 | 1209 | |
8faf50e0 XL |
1210 | pub fn unwind(&self) -> Option<&Option<BasicBlock>> { |
1211 | self.kind.unwind() | |
1212 | } | |
1213 | ||
ff7c6d11 XL |
1214 | pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { |
1215 | self.kind.unwind_mut() | |
1216 | } | |
54a0048b SL |
1217 | } |
1218 | ||
1219 | impl<'tcx> TerminatorKind<'tcx> { | |
dc9dc135 XL |
1220 | pub fn if_( |
1221 | tcx: TyCtxt<'tcx>, | |
94b46f34 XL |
1222 | cond: Operand<'tcx>, |
1223 | t: BasicBlock, | |
1224 | f: BasicBlock, | |
1225 | ) -> TerminatorKind<'tcx> { | |
0531ce1d | 1226 | static BOOL_SWITCH_FALSE: &'static [u128] = &[0]; |
8bb4bdeb XL |
1227 | TerminatorKind::SwitchInt { |
1228 | discr: cond, | |
1229 | switch_ty: tcx.types.bool, | |
1230 | values: From::from(BOOL_SWITCH_FALSE), | |
1231 | targets: vec![f, t], | |
1232 | } | |
1233 | } | |
1234 | ||
0bf4aa26 | 1235 | pub fn successors(&self) -> Successors<'_> { |
54a0048b | 1236 | use self::TerminatorKind::*; |
e9174d1e | 1237 | match *self { |
94b46f34 XL |
1238 | Resume |
1239 | | Abort | |
1240 | | GeneratorDrop | |
1241 | | Return | |
1242 | | Unreachable | |
416331ca | 1243 | | Call { destination: None, cleanup: None, .. } => None.into_iter().chain(&[]), |
94b46f34 | 1244 | Goto { target: ref t } |
416331ca XL |
1245 | | Call { destination: None, cleanup: Some(ref t), .. } |
1246 | | Call { destination: Some((_, ref t)), cleanup: None, .. } | |
1247 | | Yield { resume: ref t, drop: None, .. } | |
1248 | | DropAndReplace { target: ref t, unwind: None, .. } | |
1249 | | Drop { target: ref t, unwind: None, .. } | |
1250 | | Assert { target: ref t, cleanup: None, .. } | |
1251 | | FalseUnwind { real_target: ref t, unwind: None } => Some(t).into_iter().chain(&[]), | |
1252 | Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. } | |
1253 | | Yield { resume: ref t, drop: Some(ref u), .. } | |
1254 | | DropAndReplace { target: ref t, unwind: Some(ref u), .. } | |
1255 | | Drop { target: ref t, unwind: Some(ref u), .. } | |
1256 | | Assert { target: ref t, cleanup: Some(ref u), .. } | |
1257 | | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => { | |
1258 | Some(t).into_iter().chain(slice::from_ref(u)) | |
abe05a73 | 1259 | } |
94b46f34 | 1260 | SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]), |
416331ca XL |
1261 | FalseEdges { ref real_target, ref imaginary_target } => { |
1262 | Some(real_target).into_iter().chain(slice::from_ref(imaginary_target)) | |
1263 | } | |
e9174d1e SL |
1264 | } |
1265 | } | |
92a42be0 | 1266 | |
0bf4aa26 | 1267 | pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { |
54a0048b | 1268 | use self::TerminatorKind::*; |
92a42be0 | 1269 | match *self { |
94b46f34 XL |
1270 | Resume |
1271 | | Abort | |
1272 | | GeneratorDrop | |
1273 | | Return | |
1274 | | Unreachable | |
416331ca | 1275 | | Call { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []), |
94b46f34 | 1276 | Goto { target: ref mut t } |
416331ca XL |
1277 | | Call { destination: None, cleanup: Some(ref mut t), .. } |
1278 | | Call { destination: Some((_, ref mut t)), cleanup: None, .. } | |
1279 | | Yield { resume: ref mut t, drop: None, .. } | |
1280 | | DropAndReplace { target: ref mut t, unwind: None, .. } | |
1281 | | Drop { target: ref mut t, unwind: None, .. } | |
1282 | | Assert { target: ref mut t, cleanup: None, .. } | |
1283 | | FalseUnwind { real_target: ref mut t, unwind: None } => { | |
1284 | Some(t).into_iter().chain(&mut []) | |
abe05a73 | 1285 | } |
416331ca XL |
1286 | Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. } |
1287 | | Yield { resume: ref mut t, drop: Some(ref mut u), .. } | |
1288 | | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. } | |
1289 | | Drop { target: ref mut t, unwind: Some(ref mut u), .. } | |
1290 | | Assert { target: ref mut t, cleanup: Some(ref mut u), .. } | |
1291 | | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => { | |
1292 | Some(t).into_iter().chain(slice::from_mut(u)) | |
94b46f34 | 1293 | } |
416331ca XL |
1294 | SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]), |
1295 | FalseEdges { ref mut real_target, ref mut imaginary_target } => { | |
1296 | Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) | |
94b46f34 | 1297 | } |
92a42be0 SL |
1298 | } |
1299 | } | |
ff7c6d11 | 1300 | |
8faf50e0 XL |
1301 | pub fn unwind(&self) -> Option<&Option<BasicBlock>> { |
1302 | match *self { | |
1303 | TerminatorKind::Goto { .. } | |
1304 | | TerminatorKind::Resume | |
1305 | | TerminatorKind::Abort | |
1306 | | TerminatorKind::Return | |
1307 | | TerminatorKind::Unreachable | |
1308 | | TerminatorKind::GeneratorDrop | |
1309 | | TerminatorKind::Yield { .. } | |
1310 | | TerminatorKind::SwitchInt { .. } | |
1311 | | TerminatorKind::FalseEdges { .. } => None, | |
416331ca XL |
1312 | TerminatorKind::Call { cleanup: ref unwind, .. } |
1313 | | TerminatorKind::Assert { cleanup: ref unwind, .. } | |
8faf50e0 XL |
1314 | | TerminatorKind::DropAndReplace { ref unwind, .. } |
1315 | | TerminatorKind::Drop { ref unwind, .. } | |
1316 | | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind), | |
1317 | } | |
1318 | } | |
1319 | ||
ff7c6d11 XL |
1320 | pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { |
1321 | match *self { | |
94b46f34 XL |
1322 | TerminatorKind::Goto { .. } |
1323 | | TerminatorKind::Resume | |
1324 | | TerminatorKind::Abort | |
1325 | | TerminatorKind::Return | |
1326 | | TerminatorKind::Unreachable | |
1327 | | TerminatorKind::GeneratorDrop | |
1328 | | TerminatorKind::Yield { .. } | |
1329 | | TerminatorKind::SwitchInt { .. } | |
1330 | | TerminatorKind::FalseEdges { .. } => None, | |
416331ca XL |
1331 | TerminatorKind::Call { cleanup: ref mut unwind, .. } |
1332 | | TerminatorKind::Assert { cleanup: ref mut unwind, .. } | |
94b46f34 XL |
1333 | | TerminatorKind::DropAndReplace { ref mut unwind, .. } |
1334 | | TerminatorKind::Drop { ref mut unwind, .. } | |
1335 | | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind), | |
ff7c6d11 XL |
1336 | } |
1337 | } | |
e9174d1e SL |
1338 | } |
1339 | ||
b039eaaf | 1340 | impl<'tcx> BasicBlockData<'tcx> { |
9cc50fc6 | 1341 | pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> { |
416331ca | 1342 | BasicBlockData { statements: vec![], terminator, is_cleanup: false } |
e9174d1e | 1343 | } |
9cc50fc6 SL |
1344 | |
1345 | /// Accessor for terminator. | |
1346 | /// | |
1347 | /// Terminator may not be None after construction of the basic block is complete. This accessor | |
1348 | /// provides a convenience way to reach the terminator. | |
1349 | pub fn terminator(&self) -> &Terminator<'tcx> { | |
1350 | self.terminator.as_ref().expect("invalid terminator state") | |
1351 | } | |
1352 | ||
1353 | pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { | |
1354 | self.terminator.as_mut().expect("invalid terminator state") | |
1355 | } | |
ea8adc8c | 1356 | |
94b46f34 XL |
1357 | pub fn retain_statements<F>(&mut self, mut f: F) |
1358 | where | |
0bf4aa26 | 1359 | F: FnMut(&mut Statement<'_>) -> bool, |
94b46f34 | 1360 | { |
ea8adc8c XL |
1361 | for s in &mut self.statements { |
1362 | if !f(s) { | |
0531ce1d | 1363 | s.make_nop(); |
ea8adc8c XL |
1364 | } |
1365 | } | |
1366 | } | |
ff7c6d11 | 1367 | |
0531ce1d | 1368 | pub fn expand_statements<F, I>(&mut self, mut f: F) |
94b46f34 XL |
1369 | where |
1370 | F: FnMut(&mut Statement<'tcx>) -> Option<I>, | |
1371 | I: iter::TrustedLen<Item = Statement<'tcx>>, | |
0531ce1d XL |
1372 | { |
1373 | // Gather all the iterators we'll need to splice in, and their positions. | |
1374 | let mut splices: Vec<(usize, I)> = vec![]; | |
1375 | let mut extra_stmts = 0; | |
1376 | for (i, s) in self.statements.iter_mut().enumerate() { | |
1377 | if let Some(mut new_stmts) = f(s) { | |
1378 | if let Some(first) = new_stmts.next() { | |
1379 | // We can already store the first new statement. | |
1380 | *s = first; | |
1381 | ||
1382 | // Save the other statements for optimized splicing. | |
1383 | let remaining = new_stmts.size_hint().0; | |
1384 | if remaining > 0 { | |
1385 | splices.push((i + 1 + extra_stmts, new_stmts)); | |
1386 | extra_stmts += remaining; | |
1387 | } | |
1388 | } else { | |
1389 | s.make_nop(); | |
1390 | } | |
1391 | } | |
1392 | } | |
1393 | ||
1394 | // Splice in the new statements, from the end of the block. | |
1395 | // FIXME(eddyb) This could be more efficient with a "gap buffer" | |
1396 | // where a range of elements ("gap") is left uninitialized, with | |
1397 | // splicing adding new elements to the end of that gap and moving | |
1398 | // existing elements from before the gap to the end of the gap. | |
1399 | // For now, this is safe code, emulating a gap but initializing it. | |
94b46f34 XL |
1400 | let mut gap = self.statements.len()..self.statements.len() + extra_stmts; |
1401 | self.statements.resize( | |
1402 | gap.end, | |
1403 | Statement { | |
416331ca | 1404 | source_info: SourceInfo { span: DUMMY_SP, scope: OUTERMOST_SOURCE_SCOPE }, |
94b46f34 | 1405 | kind: StatementKind::Nop, |
0531ce1d | 1406 | }, |
94b46f34 | 1407 | ); |
0531ce1d XL |
1408 | for (splice_start, new_stmts) in splices.into_iter().rev() { |
1409 | let splice_end = splice_start + new_stmts.size_hint().0; | |
1410 | while gap.end > splice_end { | |
1411 | gap.start -= 1; | |
1412 | gap.end -= 1; | |
1413 | self.statements.swap(gap.start, gap.end); | |
1414 | } | |
1415 | self.statements.splice(splice_start..splice_end, new_stmts); | |
1416 | gap.end = splice_start; | |
1417 | } | |
1418 | } | |
1419 | ||
ff7c6d11 XL |
1420 | pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { |
1421 | if index < self.statements.len() { | |
1422 | &self.statements[index] | |
1423 | } else { | |
1424 | &self.terminator | |
1425 | } | |
1426 | } | |
e9174d1e SL |
1427 | } |
1428 | ||
54a0048b | 1429 | impl<'tcx> Debug for TerminatorKind<'tcx> { |
0bf4aa26 | 1430 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
54a0048b | 1431 | self.fmt_head(fmt)?; |
83c7162d | 1432 | let successor_count = self.successors().count(); |
9cc50fc6 | 1433 | let labels = self.fmt_successor_labels(); |
83c7162d | 1434 | assert_eq!(successor_count, labels.len()); |
9cc50fc6 | 1435 | |
83c7162d | 1436 | match successor_count { |
9cc50fc6 SL |
1437 | 0 => Ok(()), |
1438 | ||
83c7162d | 1439 | 1 => write!(fmt, " -> {:?}", self.successors().nth(0).unwrap()), |
9cc50fc6 SL |
1440 | |
1441 | _ => { | |
54a0048b | 1442 | write!(fmt, " -> [")?; |
83c7162d | 1443 | for (i, target) in self.successors().enumerate() { |
9cc50fc6 | 1444 | if i > 0 { |
54a0048b | 1445 | write!(fmt, ", ")?; |
9cc50fc6 | 1446 | } |
54a0048b | 1447 | write!(fmt, "{}: {:?}", labels[i], target)?; |
9cc50fc6 SL |
1448 | } |
1449 | write!(fmt, "]") | |
1450 | } | |
9cc50fc6 SL |
1451 | } |
1452 | } | |
1453 | } | |
1454 | ||
54a0048b | 1455 | impl<'tcx> TerminatorKind<'tcx> { |
9cc50fc6 | 1456 | /// Write the "head" part of the terminator; that is, its name and the data it uses to pick the |
3b2f2976 | 1457 | /// successor basic block, if any. The only information not included is the list of possible |
9cc50fc6 SL |
1458 | /// successors, which may be rendered differently between the text and the graphviz format. |
1459 | pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result { | |
54a0048b | 1460 | use self::TerminatorKind::*; |
e9174d1e | 1461 | match *self { |
9cc50fc6 | 1462 | Goto { .. } => write!(fmt, "goto"), |
416331ca | 1463 | SwitchInt { discr: ref place, .. } => write!(fmt, "switchInt({:?})", place), |
9cc50fc6 | 1464 | Return => write!(fmt, "return"), |
ea8adc8c | 1465 | GeneratorDrop => write!(fmt, "generator_drop"), |
9cc50fc6 | 1466 | Resume => write!(fmt, "resume"), |
ff7c6d11 | 1467 | Abort => write!(fmt, "abort"), |
ea8adc8c | 1468 | Yield { ref value, .. } => write!(fmt, "_1 = suspend({:?})", value), |
3157f602 XL |
1469 | Unreachable => write!(fmt, "unreachable"), |
1470 | Drop { ref location, .. } => write!(fmt, "drop({:?})", location), | |
416331ca XL |
1471 | DropAndReplace { ref location, ref value, .. } => { |
1472 | write!(fmt, "replace({:?} <- {:?})", location, value) | |
1473 | } | |
1474 | Call { ref func, ref args, ref destination, .. } => { | |
7453a54e | 1475 | if let Some((ref destination, _)) = *destination { |
54a0048b | 1476 | write!(fmt, "{:?} = ", destination)?; |
9cc50fc6 | 1477 | } |
54a0048b | 1478 | write!(fmt, "{:?}(", func)?; |
9cc50fc6 | 1479 | for (index, arg) in args.iter().enumerate() { |
b039eaaf | 1480 | if index > 0 { |
54a0048b | 1481 | write!(fmt, ", ")?; |
b039eaaf | 1482 | } |
54a0048b | 1483 | write!(fmt, "{:?}", arg)?; |
e9174d1e | 1484 | } |
9cc50fc6 | 1485 | write!(fmt, ")") |
e9174d1e | 1486 | } |
416331ca | 1487 | Assert { ref cond, expected, ref msg, .. } => { |
3157f602 XL |
1488 | write!(fmt, "assert(")?; |
1489 | if !expected { | |
1490 | write!(fmt, "!")?; | |
1491 | } | |
83c7162d | 1492 | write!(fmt, "{:?}, \"{:?}\")", cond, msg) |
94b46f34 | 1493 | } |
2c00a5a8 XL |
1494 | FalseEdges { .. } => write!(fmt, "falseEdges"), |
1495 | FalseUnwind { .. } => write!(fmt, "falseUnwind"), | |
e9174d1e SL |
1496 | } |
1497 | } | |
9cc50fc6 | 1498 | |
9fa01778 | 1499 | /// Returns the list of labels for the edges to the successor basic blocks. |
9cc50fc6 | 1500 | pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> { |
54a0048b | 1501 | use self::TerminatorKind::*; |
9cc50fc6 | 1502 | match *self { |
ff7c6d11 | 1503 | Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], |
7453a54e | 1504 | Goto { .. } => vec!["".into()], |
416331ca XL |
1505 | SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| { |
1506 | let param_env = ty::ParamEnv::empty(); | |
1507 | let switch_ty = tcx.lift_to_global(&switch_ty).unwrap(); | |
1508 | let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; | |
1509 | values | |
1510 | .iter() | |
1511 | .map(|&u| { | |
1512 | tcx.mk_const(ty::Const { | |
1513 | val: ConstValue::Scalar(Scalar::from_uint(u, size).into()), | |
1514 | ty: switch_ty, | |
1515 | }) | |
1516 | .to_string() | |
1517 | .into() | |
1518 | }) | |
1519 | .chain(iter::once("otherwise".into())) | |
1520 | .collect() | |
1521 | }), | |
1522 | Call { destination: Some(_), cleanup: Some(_), .. } => { | |
1523 | vec!["return".into(), "unwind".into()] | |
9cc50fc6 | 1524 | } |
416331ca XL |
1525 | Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()], |
1526 | Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()], | |
1527 | Call { destination: None, cleanup: None, .. } => vec![], | |
0bf4aa26 XL |
1528 | Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], |
1529 | Yield { drop: None, .. } => vec!["resume".into()], | |
94b46f34 | 1530 | DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => { |
0bf4aa26 | 1531 | vec!["return".into()] |
94b46f34 | 1532 | } |
416331ca XL |
1533 | DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => { |
1534 | vec!["return".into(), "unwind".into()] | |
3157f602 XL |
1535 | } |
1536 | Assert { cleanup: None, .. } => vec!["".into()], | |
0bf4aa26 | 1537 | Assert { .. } => vec!["success".into(), "unwind".into()], |
416331ca XL |
1538 | FalseEdges { .. } => vec!["real".into(), "imaginary".into()], |
1539 | FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()], | |
2c00a5a8 | 1540 | FalseUnwind { unwind: None, .. } => vec!["real".into()], |
9cc50fc6 SL |
1541 | } |
1542 | } | |
e9174d1e SL |
1543 | } |
1544 | ||
e9174d1e SL |
1545 | /////////////////////////////////////////////////////////////////////////// |
1546 | // Statements | |
1547 | ||
532ac7d7 | 1548 | #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] |
b039eaaf | 1549 | pub struct Statement<'tcx> { |
3157f602 | 1550 | pub source_info: SourceInfo, |
b039eaaf | 1551 | pub kind: StatementKind<'tcx>, |
e9174d1e SL |
1552 | } |
1553 | ||
a1dfa0c6 XL |
1554 | // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. |
1555 | #[cfg(target_arch = "x86_64")] | |
48663c56 | 1556 | static_assert_size!(Statement<'_>, 56); |
a1dfa0c6 | 1557 | |
9e0c209e SL |
1558 | impl<'tcx> Statement<'tcx> { |
1559 | /// Changes a statement to a nop. This is both faster than deleting instructions and avoids | |
1560 | /// invalidating statement indices in `Location`s. | |
1561 | pub fn make_nop(&mut self) { | |
1562 | self.kind = StatementKind::Nop | |
1563 | } | |
0531ce1d XL |
1564 | |
1565 | /// Changes a statement to a nop and returns the original statement. | |
1566 | pub fn replace_nop(&mut self) -> Self { | |
1567 | Statement { | |
1568 | source_info: self.source_info, | |
94b46f34 | 1569 | kind: mem::replace(&mut self.kind, StatementKind::Nop), |
0531ce1d XL |
1570 | } |
1571 | } | |
9e0c209e SL |
1572 | } |
1573 | ||
532ac7d7 | 1574 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
b039eaaf | 1575 | pub enum StatementKind<'tcx> { |
ff7c6d11 | 1576 | /// Write the RHS Rvalue to the LHS Place. |
0bf4aa26 | 1577 | Assign(Place<'tcx>, Box<Rvalue<'tcx>>), |
5bcae85e | 1578 | |
94b46f34 | 1579 | /// This represents all the reading that a pattern match may do |
0731742a | 1580 | /// (e.g., inspecting constants and discriminant values), and the |
0bf4aa26 XL |
1581 | /// kind of pattern it comes from. This is in order to adapt potential |
1582 | /// error messages to these specific patterns. | |
0731742a XL |
1583 | /// |
1584 | /// Note that this also is emitted for regular `let` bindings to ensure that locals that are | |
9fa01778 | 1585 | /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` |
0bf4aa26 | 1586 | FakeRead(FakeReadCause, Place<'tcx>), |
94b46f34 | 1587 | |
ff7c6d11 | 1588 | /// Write the discriminant for a variant to the enum Place. |
416331ca | 1589 | SetDiscriminant { place: Place<'tcx>, variant_index: VariantIdx }, |
5bcae85e SL |
1590 | |
1591 | /// Start a live range for the storage of the local. | |
ea8adc8c | 1592 | StorageLive(Local), |
5bcae85e SL |
1593 | |
1594 | /// End the current live range for the storage of the local. | |
ea8adc8c | 1595 | StorageDead(Local), |
9e0c209e | 1596 | |
532ac7d7 XL |
1597 | /// Executes a piece of inline Assembly. Stored in a Box to keep the size |
1598 | /// of `StatementKind` low. | |
1599 | InlineAsm(Box<InlineAsm<'tcx>>), | |
8bb4bdeb | 1600 | |
9fa01778 | 1601 | /// Retag references in the given place, ensuring they got fresh tags. This is |
a1dfa0c6 XL |
1602 | /// part of the Stacked Borrows model. These statements are currently only interpreted |
1603 | /// by miri and only generated when "-Z mir-emit-retag" is passed. | |
1604 | /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> | |
1605 | /// for more details. | |
0731742a | 1606 | Retag(RetagKind, Place<'tcx>), |
041b39d2 | 1607 | |
b7449926 XL |
1608 | /// Encodes a user's type ascription. These need to be preserved |
1609 | /// intact so that NLL can respect them. For example: | |
0531ce1d | 1610 | /// |
b7449926 | 1611 | /// let a: T = y; |
0531ce1d | 1612 | /// |
b7449926 XL |
1613 | /// The effect of this annotation is to relate the type `T_y` of the place `y` |
1614 | /// to the user-given type `T`. The effect depends on the specified variance: | |
0531ce1d | 1615 | /// |
b7449926 XL |
1616 | /// - `Covariant` -- requires that `T_y <: T` |
1617 | /// - `Contravariant` -- requires that `T_y :> T` | |
1618 | /// - `Invariant` -- requires that `T_y == T` | |
1619 | /// - `Bivariant` -- no effect | |
532ac7d7 | 1620 | AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection>), |
0531ce1d | 1621 | |
9e0c209e SL |
1622 | /// No-op. Useful for deleting instructions without affecting statement indices. |
1623 | Nop, | |
e9174d1e SL |
1624 | } |
1625 | ||
0731742a | 1626 | /// `RetagKind` describes what kind of retag is to be performed. |
532ac7d7 | 1627 | #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, HashStable)] |
0731742a XL |
1628 | pub enum RetagKind { |
1629 | /// The initial retag when entering a function | |
1630 | FnEntry, | |
1631 | /// Retag preparing for a two-phase borrow | |
1632 | TwoPhase, | |
1633 | /// Retagging raw pointers | |
1634 | Raw, | |
1635 | /// A "normal" retag | |
1636 | Default, | |
1637 | } | |
1638 | ||
0bf4aa26 | 1639 | /// The `FakeReadCause` describes the type of pattern why a `FakeRead` statement exists. |
532ac7d7 | 1640 | #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] |
0bf4aa26 | 1641 | pub enum FakeReadCause { |
9fa01778 XL |
1642 | /// Inject a fake read of the borrowed input at the end of each guards |
1643 | /// code. | |
0bf4aa26 | 1644 | /// |
9fa01778 XL |
1645 | /// This should ensure that you cannot change the variant for an enum while |
1646 | /// you are in the midst of matching on it. | |
0bf4aa26 XL |
1647 | ForMatchGuard, |
1648 | ||
1649 | /// `let x: !; match x {}` doesn't generate any read of x so we need to | |
1650 | /// generate a read of x to check that it is initialized and safe. | |
1651 | ForMatchedPlace, | |
1652 | ||
9fa01778 XL |
1653 | /// A fake read of the RefWithinGuard version of a bind-by-value variable |
1654 | /// in a match guard to ensure that it's value hasn't change by the time | |
1655 | /// we create the OutsideGuard version. | |
1656 | ForGuardBinding, | |
1657 | ||
0bf4aa26 XL |
1658 | /// Officially, the semantics of |
1659 | /// | |
1660 | /// `let pattern = <expr>;` | |
1661 | /// | |
1662 | /// is that `<expr>` is evaluated into a temporary and then this temporary is | |
1663 | /// into the pattern. | |
1664 | /// | |
1665 | /// However, if we see the simple pattern `let var = <expr>`, we optimize this to | |
1666 | /// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable, | |
1667 | /// but in some cases it can affect the borrow checker, as in #53695. | |
1668 | /// Therefore, we insert a "fake read" here to ensure that we get | |
1669 | /// appropriate errors. | |
1670 | ForLet, | |
1671 | } | |
1672 | ||
532ac7d7 XL |
1673 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
1674 | pub struct InlineAsm<'tcx> { | |
1675 | pub asm: HirInlineAsm, | |
1676 | pub outputs: Box<[Place<'tcx>]>, | |
1677 | pub inputs: Box<[(Span, Operand<'tcx>)]>, | |
1678 | } | |
1679 | ||
b039eaaf | 1680 | impl<'tcx> Debug for Statement<'tcx> { |
0bf4aa26 | 1681 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
1682 | use self::StatementKind::*; |
1683 | match self.kind { | |
ff7c6d11 | 1684 | Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv), |
0bf4aa26 | 1685 | FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place), |
416331ca XL |
1686 | Retag(ref kind, ref place) => write!( |
1687 | fmt, | |
1688 | "Retag({}{:?})", | |
1689 | match kind { | |
1690 | RetagKind::FnEntry => "[fn entry] ", | |
1691 | RetagKind::TwoPhase => "[2phase] ", | |
1692 | RetagKind::Raw => "[raw] ", | |
1693 | RetagKind::Default => "", | |
1694 | }, | |
1695 | place, | |
1696 | ), | |
ff7c6d11 XL |
1697 | StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place), |
1698 | StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place), | |
416331ca XL |
1699 | SetDiscriminant { ref place, variant_index } => { |
1700 | write!(fmt, "discriminant({:?}) = {:?}", place, variant_index) | |
1701 | } | |
1702 | InlineAsm(ref asm) => { | |
1703 | write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs) | |
1704 | } | |
b7449926 XL |
1705 | AscribeUserType(ref place, ref variance, ref c_ty) => { |
1706 | write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) | |
94b46f34 | 1707 | } |
9e0c209e | 1708 | Nop => write!(fmt, "nop"), |
e9174d1e SL |
1709 | } |
1710 | } | |
1711 | } | |
54a0048b | 1712 | |
e9174d1e | 1713 | /////////////////////////////////////////////////////////////////////////// |
ff7c6d11 | 1714 | // Places |
e9174d1e SL |
1715 | |
1716 | /// A path to a value; something that can be evaluated without | |
1717 | /// changing or disturbing program state. | |
416331ca XL |
1718 | #[derive( |
1719 | Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, | |
1720 | )] | |
1721 | pub struct Place<'tcx> { | |
1722 | pub base: PlaceBase<'tcx>, | |
532ac7d7 XL |
1723 | |
1724 | /// projection out of a place (access a field, deref a pointer, etc) | |
416331ca | 1725 | pub projection: Option<Box<Projection<'tcx>>>, |
532ac7d7 XL |
1726 | } |
1727 | ||
416331ca XL |
1728 | #[derive( |
1729 | Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, | |
1730 | )] | |
532ac7d7 | 1731 | pub enum PlaceBase<'tcx> { |
c30ab7b3 SL |
1732 | /// local variable |
1733 | Local(Local), | |
e9174d1e SL |
1734 | |
1735 | /// static or static mut variable | |
8bb4bdeb | 1736 | Static(Box<Static<'tcx>>), |
e9174d1e SL |
1737 | } |
1738 | ||
532ac7d7 | 1739 | /// We store the normalized type to avoid requiring normalization when reading MIR |
0bf4aa26 | 1740 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] |
8bb4bdeb | 1741 | pub struct Static<'tcx> { |
8bb4bdeb | 1742 | pub ty: Ty<'tcx>, |
532ac7d7 XL |
1743 | pub kind: StaticKind, |
1744 | } | |
1745 | ||
416331ca XL |
1746 | #[derive( |
1747 | Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, RustcEncodable, RustcDecodable, | |
1748 | )] | |
532ac7d7 XL |
1749 | pub enum StaticKind { |
1750 | Promoted(Promoted), | |
1751 | Static(DefId), | |
8bb4bdeb XL |
1752 | } |
1753 | ||
cc61c64b | 1754 | impl_stable_hash_for!(struct Static<'tcx> { |
532ac7d7 XL |
1755 | ty, |
1756 | kind | |
cc61c64b XL |
1757 | }); |
1758 | ||
dc9dc135 | 1759 | /// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`. |
416331ca XL |
1760 | #[derive( |
1761 | Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, | |
1762 | )] | |
dc9dc135 | 1763 | pub struct Projection<'tcx> { |
416331ca | 1764 | pub base: Option<Box<Projection<'tcx>>>, |
dc9dc135 | 1765 | pub elem: PlaceElem<'tcx>, |
416331ca | 1766 | } |
e9174d1e | 1767 | |
416331ca XL |
1768 | #[derive( |
1769 | Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, | |
1770 | )] | |
532ac7d7 | 1771 | pub enum ProjectionElem<V, T> { |
e9174d1e | 1772 | Deref, |
3b2f2976 | 1773 | Field(Field, T), |
e9174d1e SL |
1774 | Index(V), |
1775 | ||
7453a54e SL |
1776 | /// These indices are generated by slice patterns. Easiest to explain |
1777 | /// by example: | |
1778 | /// | |
1779 | /// ``` | |
1780 | /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, | |
1781 | /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, | |
1782 | /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, | |
1783 | /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, | |
1784 | /// ``` | |
e9174d1e | 1785 | ConstantIndex { |
7453a54e SL |
1786 | /// index or -index (in Python terms), depending on from_end |
1787 | offset: u32, | |
1788 | /// thing being indexed must be at least this long | |
1789 | min_length: u32, | |
1790 | /// counting backwards from end? | |
1791 | from_end: bool, | |
e9174d1e SL |
1792 | }, |
1793 | ||
3157f602 XL |
1794 | /// These indices are generated by slice patterns. |
1795 | /// | |
1796 | /// slice[from:-to] in Python terms. | |
1797 | Subslice { | |
1798 | from: u32, | |
1799 | to: u32, | |
1800 | }, | |
1801 | ||
7453a54e SL |
1802 | /// "Downcast" to a variant of an ADT. Currently, we only introduce |
1803 | /// this for ADTs with more than one variant. It may be better to | |
1804 | /// just introduce it always, or always for enums. | |
532ac7d7 XL |
1805 | /// |
1806 | /// The included Symbol is the name of the variant, used for printing MIR. | |
1807 | Downcast(Option<Symbol>, VariantIdx), | |
e9174d1e SL |
1808 | } |
1809 | ||
ff7c6d11 | 1810 | /// Alias for projections as they appear in places, where the base is a place |
ea8adc8c | 1811 | /// and the index is a local. |
532ac7d7 | 1812 | pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; |
e9174d1e | 1813 | |
48663c56 XL |
1814 | // At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. |
1815 | #[cfg(target_arch = "x86_64")] | |
1816 | static_assert_size!(PlaceElem<'_>, 16); | |
a1dfa0c6 | 1817 | |
0bf4aa26 XL |
1818 | /// Alias for projections as they appear in `UserTypeProjection`, where we |
1819 | /// need neither the `V` parameter for `Index` nor the `T` for `Field`. | |
532ac7d7 | 1820 | pub type ProjectionKind = ProjectionElem<(), ()>; |
0bf4aa26 | 1821 | |
b7449926 XL |
1822 | newtype_index! { |
1823 | pub struct Field { | |
532ac7d7 | 1824 | derive [HashStable] |
b7449926 XL |
1825 | DEBUG_FORMAT = "field[{}]" |
1826 | } | |
1827 | } | |
e9174d1e | 1828 | |
416331ca XL |
1829 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
1830 | pub struct PlaceRef<'a, 'tcx> { | |
1831 | pub base: &'a PlaceBase<'tcx>, | |
1832 | pub projection: &'a Option<Box<Projection<'tcx>>>, | |
1833 | } | |
1834 | ||
ff7c6d11 | 1835 | impl<'tcx> Place<'tcx> { |
416331ca XL |
1836 | pub const RETURN_PLACE: Place<'tcx> = Place { |
1837 | base: PlaceBase::Local(RETURN_PLACE), | |
1838 | projection: None, | |
1839 | }; | |
532ac7d7 | 1840 | |
ff7c6d11 | 1841 | pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> { |
7453a54e | 1842 | self.elem(ProjectionElem::Field(f, ty)) |
e9174d1e SL |
1843 | } |
1844 | ||
ff7c6d11 | 1845 | pub fn deref(self) -> Place<'tcx> { |
e9174d1e SL |
1846 | self.elem(ProjectionElem::Deref) |
1847 | } | |
1848 | ||
a1dfa0c6 | 1849 | pub fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Place<'tcx> { |
532ac7d7 XL |
1850 | self.elem(ProjectionElem::Downcast( |
1851 | Some(adt_def.variants[variant_index].ident.name), | |
416331ca XL |
1852 | variant_index, |
1853 | )) | |
32a655c1 SL |
1854 | } |
1855 | ||
48663c56 XL |
1856 | pub fn downcast_unnamed(self, variant_index: VariantIdx) -> Place<'tcx> { |
1857 | self.elem(ProjectionElem::Downcast(None, variant_index)) | |
1858 | } | |
1859 | ||
ff7c6d11 | 1860 | pub fn index(self, index: Local) -> Place<'tcx> { |
e9174d1e SL |
1861 | self.elem(ProjectionElem::Index(index)) |
1862 | } | |
1863 | ||
ff7c6d11 | 1864 | pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> { |
416331ca XL |
1865 | Place { |
1866 | base: self.base, | |
1867 | projection: Some(Box::new(Projection { base: self.projection, elem })), | |
1868 | } | |
e9174d1e | 1869 | } |
0bf4aa26 | 1870 | |
9fa01778 | 1871 | /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or |
0bf4aa26 | 1872 | /// a single deref of a local. |
9fa01778 XL |
1873 | // |
1874 | // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? | |
dc9dc135 | 1875 | pub fn local_or_deref_local(&self) -> Option<Local> { |
0bf4aa26 | 1876 | match self { |
416331ca XL |
1877 | Place { |
1878 | base: PlaceBase::Local(local), | |
1879 | projection: None, | |
1880 | } | | |
1881 | Place { | |
1882 | base: PlaceBase::Local(local), | |
1883 | projection: Some(box Projection { | |
1884 | base: None, | |
1885 | elem: ProjectionElem::Deref, | |
1886 | }), | |
1887 | } => Some(*local), | |
0bf4aa26 XL |
1888 | _ => None, |
1889 | } | |
1890 | } | |
1891 | ||
48663c56 | 1892 | /// Recursively "iterates" over place components, generating a `PlaceBase` and |
dc9dc135 | 1893 | /// `Projections` list and invoking `op` with a `ProjectionsIter`. |
48663c56 XL |
1894 | pub fn iterate<R>( |
1895 | &self, | |
dc9dc135 | 1896 | op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, |
48663c56 | 1897 | ) -> R { |
416331ca | 1898 | Place::iterate_over(&self.base, &self.projection, op) |
48663c56 XL |
1899 | } |
1900 | ||
416331ca XL |
1901 | pub fn iterate_over<R>( |
1902 | place_base: &PlaceBase<'tcx>, | |
1903 | place_projection: &Option<Box<Projection<'tcx>>>, | |
dc9dc135 | 1904 | op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, |
48663c56 | 1905 | ) -> R { |
416331ca XL |
1906 | fn iterate_over2<'tcx, R>( |
1907 | place_base: &PlaceBase<'tcx>, | |
1908 | place_projection: &Option<Box<Projection<'tcx>>>, | |
1909 | next: &Projections<'_, 'tcx>, | |
1910 | op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, | |
1911 | ) -> R { | |
1912 | match place_projection { | |
1913 | None => { | |
1914 | op(place_base, next.iter()) | |
1915 | } | |
1916 | ||
1917 | Some(interior) => { | |
1918 | iterate_over2( | |
1919 | place_base, | |
1920 | &interior.base, | |
1921 | &Projections::List { | |
1922 | projection: interior, | |
1923 | next, | |
1924 | }, | |
1925 | op, | |
1926 | ) | |
1927 | } | |
1928 | } | |
1929 | } | |
48663c56 | 1930 | |
416331ca XL |
1931 | iterate_over2(place_base, place_projection, &Projections::Empty, op) |
1932 | } | |
1933 | ||
1934 | pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> { | |
1935 | PlaceRef { | |
1936 | base: &self.base, | |
1937 | projection: &self.projection, | |
0bf4aa26 XL |
1938 | } |
1939 | } | |
e9174d1e SL |
1940 | } |
1941 | ||
dc9dc135 XL |
1942 | impl From<Local> for Place<'_> { |
1943 | fn from(local: Local) -> Self { | |
416331ca XL |
1944 | Place { |
1945 | base: local.into(), | |
1946 | projection: None, | |
1947 | } | |
dc9dc135 XL |
1948 | } |
1949 | } | |
1950 | ||
1951 | impl From<Local> for PlaceBase<'_> { | |
1952 | fn from(local: Local) -> Self { | |
1953 | PlaceBase::Local(local) | |
1954 | } | |
1955 | } | |
1956 | ||
416331ca XL |
1957 | impl<'a, 'tcx> PlaceRef<'a, 'tcx> { |
1958 | pub fn iterate<R>( | |
1959 | &self, | |
1960 | op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, | |
1961 | ) -> R { | |
1962 | Place::iterate_over(self.base, self.projection, op) | |
1963 | } | |
1964 | ||
1965 | /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or | |
1966 | /// a single deref of a local. | |
1967 | // | |
1968 | // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? | |
1969 | pub fn local_or_deref_local(&self) -> Option<Local> { | |
1970 | match self { | |
1971 | PlaceRef { | |
1972 | base: PlaceBase::Local(local), | |
1973 | projection: None, | |
1974 | } | | |
1975 | PlaceRef { | |
1976 | base: PlaceBase::Local(local), | |
1977 | projection: Some(box Projection { | |
1978 | base: None, | |
1979 | elem: ProjectionElem::Deref, | |
1980 | }), | |
1981 | } => Some(*local), | |
1982 | _ => None, | |
1983 | } | |
1984 | } | |
1985 | } | |
1986 | ||
48663c56 XL |
1987 | /// A linked list of projections running up the stack; begins with the |
1988 | /// innermost projection and extends to the outermost (e.g., `a.b.c` | |
1989 | /// would have the place `b` with a "next" pointer to `b.c`). | |
1990 | /// Created by `Place::iterate`. | |
1991 | /// | |
1992 | /// N.B., this particular impl strategy is not the most obvious. It was | |
1993 | /// chosen because it makes a measurable difference to NLL | |
1994 | /// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot. | |
dc9dc135 | 1995 | pub enum Projections<'p, 'tcx> { |
48663c56 XL |
1996 | Empty, |
1997 | ||
416331ca | 1998 | List { projection: &'p Projection<'tcx>, next: &'p Projections<'p, 'tcx> }, |
48663c56 XL |
1999 | } |
2000 | ||
dc9dc135 XL |
2001 | impl<'p, 'tcx> Projections<'p, 'tcx> { |
2002 | fn iter(&self) -> ProjectionsIter<'_, 'tcx> { | |
2003 | ProjectionsIter { value: self } | |
48663c56 XL |
2004 | } |
2005 | } | |
2006 | ||
dc9dc135 XL |
2007 | impl<'p, 'tcx> IntoIterator for &'p Projections<'p, 'tcx> { |
2008 | type Item = &'p Projection<'tcx>; | |
2009 | type IntoIter = ProjectionsIter<'p, 'tcx>; | |
48663c56 | 2010 | |
dc9dc135 | 2011 | /// Converts a list of `Projection` components into an iterator; |
48663c56 XL |
2012 | /// this iterator yields up a never-ending stream of `Option<&Place>`. |
2013 | /// These begin with the "innermost" projection and then with each | |
2014 | /// projection therefrom. So given a place like `a.b.c` it would | |
2015 | /// yield up: | |
2016 | /// | |
2017 | /// ```notrust | |
2018 | /// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ... | |
2019 | /// ``` | |
2020 | fn into_iter(self) -> Self::IntoIter { | |
2021 | self.iter() | |
2022 | } | |
2023 | } | |
2024 | ||
dc9dc135 | 2025 | /// Iterator over components; see `Projections::iter` for more |
48663c56 XL |
2026 | /// information. |
2027 | /// | |
2028 | /// N.B., this is not a *true* Rust iterator -- the code above just | |
2029 | /// manually invokes `next`. This is because we (sometimes) want to | |
2030 | /// keep executing even after `None` has been returned. | |
dc9dc135 XL |
2031 | pub struct ProjectionsIter<'p, 'tcx> { |
2032 | pub value: &'p Projections<'p, 'tcx>, | |
48663c56 XL |
2033 | } |
2034 | ||
dc9dc135 XL |
2035 | impl<'p, 'tcx> Iterator for ProjectionsIter<'p, 'tcx> { |
2036 | type Item = &'p Projection<'tcx>; | |
48663c56 XL |
2037 | |
2038 | fn next(&mut self) -> Option<Self::Item> { | |
dc9dc135 | 2039 | if let &Projections::List { projection, next } = self.value { |
48663c56 XL |
2040 | self.value = next; |
2041 | Some(projection) | |
2042 | } else { | |
2043 | None | |
2044 | } | |
2045 | } | |
2046 | } | |
2047 | ||
dc9dc135 | 2048 | impl<'p, 'tcx> FusedIterator for ProjectionsIter<'p, 'tcx> {} |
48663c56 | 2049 | |
ff7c6d11 | 2050 | impl<'tcx> Debug for Place<'tcx> { |
0bf4aa26 | 2051 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
48663c56 XL |
2052 | self.iterate(|_place_base, place_projections| { |
2053 | // FIXME: remove this collect once we have migrated to slices | |
2054 | let projs_vec: Vec<_> = place_projections.collect(); | |
2055 | for projection in projs_vec.iter().rev() { | |
2056 | match projection.elem { | |
416331ca | 2057 | ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { |
48663c56 XL |
2058 | write!(fmt, "(").unwrap(); |
2059 | } | |
2060 | ProjectionElem::Deref => { | |
2061 | write!(fmt, "(*").unwrap(); | |
2062 | } | |
416331ca XL |
2063 | ProjectionElem::Index(_) |
2064 | | ProjectionElem::ConstantIndex { .. } | |
2065 | | ProjectionElem::Subslice { .. } => {} | |
94b46f34 | 2066 | } |
48663c56 XL |
2067 | } |
2068 | }); | |
2069 | ||
2070 | self.iterate(|place_base, place_projections| { | |
dc9dc135 | 2071 | write!(fmt, "{:?}", place_base)?; |
48663c56 XL |
2072 | |
2073 | for projection in place_projections { | |
2074 | match projection.elem { | |
2075 | ProjectionElem::Downcast(Some(name), _index) => { | |
2076 | write!(fmt, " as {})", name)?; | |
2077 | } | |
2078 | ProjectionElem::Downcast(None, index) => { | |
2079 | write!(fmt, " as variant#{:?})", index)?; | |
2080 | } | |
2081 | ProjectionElem::Deref => { | |
2082 | write!(fmt, ")")?; | |
2083 | } | |
2084 | ProjectionElem::Field(field, ty) => { | |
2085 | write!(fmt, ".{:?}: {:?})", field.index(), ty)?; | |
2086 | } | |
2087 | ProjectionElem::Index(ref index) => { | |
2088 | write!(fmt, "[{:?}]", index)?; | |
2089 | } | |
416331ca | 2090 | ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { |
48663c56 XL |
2091 | write!(fmt, "[{:?} of {:?}]", offset, min_length)?; |
2092 | } | |
416331ca | 2093 | ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { |
48663c56 XL |
2094 | write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; |
2095 | } | |
2096 | ProjectionElem::Subslice { from, to } if to == 0 => { | |
2097 | write!(fmt, "[{:?}:]", from)?; | |
2098 | } | |
2099 | ProjectionElem::Subslice { from, to } if from == 0 => { | |
2100 | write!(fmt, "[:-{:?}]", to)?; | |
2101 | } | |
2102 | ProjectionElem::Subslice { from, to } => { | |
2103 | write!(fmt, "[{:?}:-{:?}]", from, to)?; | |
2104 | } | |
94b46f34 | 2105 | } |
48663c56 XL |
2106 | } |
2107 | ||
2108 | Ok(()) | |
2109 | }) | |
e9174d1e SL |
2110 | } |
2111 | } | |
2112 | ||
dc9dc135 XL |
2113 | impl Debug for PlaceBase<'_> { |
2114 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { | |
2115 | match *self { | |
2116 | PlaceBase::Local(id) => write!(fmt, "{:?}", id), | |
2117 | PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) }) => { | |
416331ca XL |
2118 | write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.def_path_str(def_id)), ty) |
2119 | } | |
dc9dc135 | 2120 | PlaceBase::Static(box self::Static { ty, kind: StaticKind::Promoted(promoted) }) => { |
416331ca XL |
2121 | write!(fmt, "({:?}: {:?})", promoted, ty) |
2122 | } | |
dc9dc135 XL |
2123 | } |
2124 | } | |
2125 | } | |
2126 | ||
54a0048b SL |
2127 | /////////////////////////////////////////////////////////////////////////// |
2128 | // Scopes | |
2129 | ||
b7449926 XL |
2130 | newtype_index! { |
2131 | pub struct SourceScope { | |
532ac7d7 | 2132 | derive [HashStable] |
abe05a73 | 2133 | DEBUG_FORMAT = "scope[{}]", |
94b46f34 | 2134 | const OUTERMOST_SOURCE_SCOPE = 0, |
b7449926 XL |
2135 | } |
2136 | } | |
54a0048b | 2137 | |
532ac7d7 | 2138 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
94b46f34 | 2139 | pub struct SourceScopeData { |
a7813a04 | 2140 | pub span: Span, |
94b46f34 XL |
2141 | pub parent_scope: Option<SourceScope>, |
2142 | } | |
2143 | ||
532ac7d7 | 2144 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
94b46f34 | 2145 | pub struct SourceScopeLocalData { |
532ac7d7 XL |
2146 | /// A HirId with lint levels equivalent to this scope's lint levels. |
2147 | pub lint_root: hir::HirId, | |
94b46f34 XL |
2148 | /// The unsafe block that contains this node. |
2149 | pub safety: Safety, | |
54a0048b SL |
2150 | } |
2151 | ||
e9174d1e SL |
2152 | /////////////////////////////////////////////////////////////////////////// |
2153 | // Operands | |
54a0048b | 2154 | |
0bf4aa26 XL |
2155 | /// These are values that can appear inside an rvalue. They are intentionally |
2156 | /// limited to prevent rvalues from being nested in one another. | |
532ac7d7 | 2157 | #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] |
b039eaaf | 2158 | pub enum Operand<'tcx> { |
ff7c6d11 XL |
2159 | /// Copy: The value must be available for use afterwards. |
2160 | /// | |
2161 | /// This implies that the type of the place must be `Copy`; this is true | |
2162 | /// by construction during build, but also checked by the MIR type checker. | |
2163 | Copy(Place<'tcx>), | |
b7449926 | 2164 | |
ff7c6d11 XL |
2165 | /// Move: The value (including old borrows of it) will not be used again. |
2166 | /// | |
2167 | /// Safe for values of all types (modulo future developments towards `?Move`). | |
2168 | /// Correct usage patterns are enforced by the borrow checker for safe code. | |
2169 | /// `Copy` may be converted to `Move` to enable "last-use" optimizations. | |
2170 | Move(Place<'tcx>), | |
b7449926 XL |
2171 | |
2172 | /// Synthesizes a constant value. | |
cc61c64b | 2173 | Constant(Box<Constant<'tcx>>), |
e9174d1e SL |
2174 | } |
2175 | ||
b039eaaf | 2176 | impl<'tcx> Debug for Operand<'tcx> { |
0bf4aa26 | 2177 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
2178 | use self::Operand::*; |
2179 | match *self { | |
2180 | Constant(ref a) => write!(fmt, "{:?}", a), | |
ff7c6d11 XL |
2181 | Copy(ref place) => write!(fmt, "{:?}", place), |
2182 | Move(ref place) => write!(fmt, "move {:?}", place), | |
e9174d1e SL |
2183 | } |
2184 | } | |
2185 | } | |
2186 | ||
cc61c64b | 2187 | impl<'tcx> Operand<'tcx> { |
b7449926 | 2188 | /// Convenience helper to make a constant that refers to the fn |
9fa01778 | 2189 | /// with given `DefId` and substs. Since this is used to synthesize |
b7449926 | 2190 | /// MIR, assumes `user_ty` is None. |
dc9dc135 XL |
2191 | pub fn function_handle( |
2192 | tcx: TyCtxt<'tcx>, | |
cc61c64b | 2193 | def_id: DefId, |
532ac7d7 | 2194 | substs: SubstsRef<'tcx>, |
cc61c64b XL |
2195 | span: Span, |
2196 | ) -> Self { | |
ea8adc8c | 2197 | let ty = tcx.type_of(def_id).subst(tcx, substs); |
cc61c64b | 2198 | Operand::Constant(box Constant { |
041b39d2 | 2199 | span, |
ea8adc8c | 2200 | ty, |
b7449926 | 2201 | user_ty: None, |
dc9dc135 | 2202 | literal: ty::Const::zero_sized(tcx, ty), |
cc61c64b XL |
2203 | }) |
2204 | } | |
2205 | ||
ff7c6d11 XL |
2206 | pub fn to_copy(&self) -> Self { |
2207 | match *self { | |
2208 | Operand::Copy(_) | Operand::Constant(_) => self.clone(), | |
94b46f34 | 2209 | Operand::Move(ref place) => Operand::Copy(place.clone()), |
ff7c6d11 XL |
2210 | } |
2211 | } | |
cc61c64b XL |
2212 | } |
2213 | ||
e9174d1e | 2214 | /////////////////////////////////////////////////////////////////////////// |
7453a54e | 2215 | /// Rvalues |
e9174d1e | 2216 | |
532ac7d7 | 2217 | #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] |
b039eaaf | 2218 | pub enum Rvalue<'tcx> { |
7453a54e | 2219 | /// x (either a move or copy, depending on type of x) |
b039eaaf | 2220 | Use(Operand<'tcx>), |
e9174d1e | 2221 | |
7453a54e | 2222 | /// [x; 32] |
0531ce1d | 2223 | Repeat(Operand<'tcx>, u64), |
e9174d1e | 2224 | |
7453a54e | 2225 | /// &x or &mut x |
ff7c6d11 | 2226 | Ref(Region<'tcx>, BorrowKind, Place<'tcx>), |
e9174d1e | 2227 | |
7453a54e | 2228 | /// length of a [X] or [X;n] value |
ff7c6d11 | 2229 | Len(Place<'tcx>), |
e9174d1e | 2230 | |
b039eaaf | 2231 | Cast(CastKind, Operand<'tcx>, Ty<'tcx>), |
e9174d1e | 2232 | |
b039eaaf | 2233 | BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), |
3157f602 | 2234 | CheckedBinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), |
e9174d1e | 2235 | |
7cac9316 | 2236 | NullaryOp(NullOp, Ty<'tcx>), |
b039eaaf | 2237 | UnaryOp(UnOp, Operand<'tcx>), |
e9174d1e | 2238 | |
8bb4bdeb XL |
2239 | /// Read the discriminant of an ADT. |
2240 | /// | |
0731742a | 2241 | /// Undefined (i.e., no effort is made to make it defined, but there’s no reason why it cannot |
8bb4bdeb | 2242 | /// be defined to return, say, a 0) if ADT is not an enum. |
ff7c6d11 | 2243 | Discriminant(Place<'tcx>), |
8bb4bdeb | 2244 | |
9fa01778 | 2245 | /// Creates an aggregate value, like a tuple or struct. This is |
7453a54e SL |
2246 | /// only needed because we want to distinguish `dest = Foo { x: |
2247 | /// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case | |
2248 | /// that `Foo` has a destructor. These rvalues can be optimized | |
2249 | /// away after type-checking and before lowering. | |
cc61c64b | 2250 | Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), |
e9174d1e SL |
2251 | } |
2252 | ||
532ac7d7 | 2253 | #[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] |
e9174d1e SL |
2254 | pub enum CastKind { |
2255 | Misc, | |
48663c56 | 2256 | Pointer(PointerCast), |
e9174d1e SL |
2257 | } |
2258 | ||
532ac7d7 | 2259 | #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] |
b039eaaf | 2260 | pub enum AggregateKind<'tcx> { |
8bb4bdeb XL |
2261 | /// The type is of the element |
2262 | Array(Ty<'tcx>), | |
e9174d1e | 2263 | Tuple, |
ff7c6d11 | 2264 | |
2c00a5a8 XL |
2265 | /// The second field is the variant index. It's equal to 0 for struct |
2266 | /// and union expressions. The fourth field is | |
ff7c6d11 | 2267 | /// active field number and is present only for union expressions |
0731742a | 2268 | /// -- e.g., for a union expression `SomeUnion { c: .. }`, the |
ff7c6d11 | 2269 | /// active field index would identity the field `c` |
416331ca | 2270 | Adt(&'tcx AdtDef, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), |
ff7c6d11 | 2271 | |
a7813a04 | 2272 | Closure(DefId, ClosureSubsts<'tcx>), |
94b46f34 | 2273 | Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), |
e9174d1e SL |
2274 | } |
2275 | ||
532ac7d7 | 2276 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] |
e9174d1e SL |
2277 | pub enum BinOp { |
2278 | /// The `+` operator (addition) | |
2279 | Add, | |
2280 | /// The `-` operator (subtraction) | |
2281 | Sub, | |
2282 | /// The `*` operator (multiplication) | |
2283 | Mul, | |
2284 | /// The `/` operator (division) | |
2285 | Div, | |
2286 | /// The `%` operator (modulus) | |
2287 | Rem, | |
2288 | /// The `^` operator (bitwise xor) | |
2289 | BitXor, | |
2290 | /// The `&` operator (bitwise and) | |
2291 | BitAnd, | |
2292 | /// The `|` operator (bitwise or) | |
2293 | BitOr, | |
2294 | /// The `<<` operator (shift left) | |
2295 | Shl, | |
2296 | /// The `>>` operator (shift right) | |
2297 | Shr, | |
2298 | /// The `==` operator (equality) | |
2299 | Eq, | |
2300 | /// The `<` operator (less than) | |
2301 | Lt, | |
2302 | /// The `<=` operator (less than or equal to) | |
2303 | Le, | |
2304 | /// The `!=` operator (not equal to) | |
2305 | Ne, | |
2306 | /// The `>=` operator (greater than or equal to) | |
2307 | Ge, | |
2308 | /// The `>` operator (greater than) | |
2309 | Gt, | |
7cac9316 XL |
2310 | /// The `ptr.offset` operator |
2311 | Offset, | |
e9174d1e SL |
2312 | } |
2313 | ||
3157f602 XL |
2314 | impl BinOp { |
2315 | pub fn is_checkable(self) -> bool { | |
2316 | use self::BinOp::*; | |
2317 | match self { | |
2318 | Add | Sub | Mul | Shl | Shr => true, | |
94b46f34 | 2319 | _ => false, |
3157f602 XL |
2320 | } |
2321 | } | |
2322 | } | |
2323 | ||
532ac7d7 | 2324 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] |
7cac9316 | 2325 | pub enum NullOp { |
9fa01778 | 2326 | /// Returns the size of a value of that type |
7cac9316 | 2327 | SizeOf, |
9fa01778 | 2328 | /// Creates a new uninitialized box for a value of that type |
7cac9316 XL |
2329 | Box, |
2330 | } | |
2331 | ||
532ac7d7 | 2332 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] |
e9174d1e SL |
2333 | pub enum UnOp { |
2334 | /// The `!` operator for logical inversion | |
2335 | Not, | |
2336 | /// The `-` operator for negation | |
b039eaaf | 2337 | Neg, |
e9174d1e SL |
2338 | } |
2339 | ||
b039eaaf | 2340 | impl<'tcx> Debug for Rvalue<'tcx> { |
0bf4aa26 | 2341 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
2342 | use self::Rvalue::*; |
2343 | ||
2344 | match *self { | |
ff7c6d11 | 2345 | Use(ref place) => write!(fmt, "{:?}", place), |
e9174d1e | 2346 | Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b), |
9cc50fc6 | 2347 | Len(ref a) => write!(fmt, "Len({:?})", a), |
ff7c6d11 XL |
2348 | Cast(ref kind, ref place, ref ty) => { |
2349 | write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind) | |
2350 | } | |
9cc50fc6 | 2351 | BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b), |
3157f602 XL |
2352 | CheckedBinaryOp(ref op, ref a, ref b) => { |
2353 | write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b) | |
2354 | } | |
e9174d1e | 2355 | UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), |
ff7c6d11 | 2356 | Discriminant(ref place) => write!(fmt, "discriminant({:?})", place), |
7cac9316 | 2357 | NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), |
ff7c6d11 | 2358 | Ref(region, borrow_kind, ref place) => { |
9cc50fc6 SL |
2359 | let kind_str = match borrow_kind { |
2360 | BorrowKind::Shared => "", | |
0bf4aa26 | 2361 | BorrowKind::Shallow => "shallow ", |
2c00a5a8 | 2362 | BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", |
9cc50fc6 | 2363 | }; |
041b39d2 | 2364 | |
3b2f2976 | 2365 | // When printing regions, add trailing space if necessary. |
532ac7d7 XL |
2366 | let print_region = ty::tls::with(|tcx| { |
2367 | tcx.sess.verbose() || tcx.sess.opts.debugging_opts.identify_regions | |
2368 | }); | |
2369 | let region = if print_region { | |
8faf50e0 | 2370 | let mut region = region.to_string(); |
94b46f34 XL |
2371 | if region.len() > 0 { |
2372 | region.push(' '); | |
2373 | } | |
041b39d2 XL |
2374 | region |
2375 | } else { | |
3b2f2976 | 2376 | // Do not even print 'static |
b7449926 | 2377 | String::new() |
041b39d2 | 2378 | }; |
ff7c6d11 | 2379 | write!(fmt, "&{}{}{:?}", region, kind_str, place) |
9cc50fc6 SL |
2380 | } |
2381 | ||
ff7c6d11 | 2382 | Aggregate(ref kind, ref places) => { |
0bf4aa26 | 2383 | fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result { |
54a0048b | 2384 | let mut tuple_fmt = fmt.debug_tuple(""); |
ff7c6d11 XL |
2385 | for place in places { |
2386 | tuple_fmt.field(place); | |
9cc50fc6 SL |
2387 | } |
2388 | tuple_fmt.finish() | |
2389 | } | |
2390 | ||
cc61c64b | 2391 | match **kind { |
ff7c6d11 | 2392 | AggregateKind::Array(_) => write!(fmt, "{:?}", places), |
9cc50fc6 | 2393 | |
94b46f34 XL |
2394 | AggregateKind::Tuple => match places.len() { |
2395 | 0 => write!(fmt, "()"), | |
2396 | 1 => write!(fmt, "({:?},)", places[0]), | |
2397 | _ => fmt_tuple(fmt, places), | |
2398 | }, | |
9cc50fc6 | 2399 | |
b7449926 | 2400 | AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => { |
9cc50fc6 | 2401 | let variant_def = &adt_def.variants[variant]; |
54a0048b | 2402 | |
532ac7d7 XL |
2403 | let f = &mut *fmt; |
2404 | ty::tls::with(|tcx| { | |
2405 | let substs = tcx.lift(&substs).expect("could not lift for printing"); | |
2406 | FmtPrinter::new(tcx, f, Namespace::ValueNS) | |
2407 | .print_def_path(variant_def.def_id, substs)?; | |
2408 | Ok(()) | |
2409 | })?; | |
9cc50fc6 | 2410 | |
c30ab7b3 SL |
2411 | match variant_def.ctor_kind { |
2412 | CtorKind::Const => Ok(()), | |
ff7c6d11 | 2413 | CtorKind::Fn => fmt_tuple(fmt, places), |
c30ab7b3 | 2414 | CtorKind::Fictive => { |
54a0048b | 2415 | let mut struct_fmt = fmt.debug_struct(""); |
ff7c6d11 | 2416 | for (field, place) in variant_def.fields.iter().zip(places) { |
94b46f34 | 2417 | struct_fmt.field(&field.ident.as_str(), place); |
9cc50fc6 SL |
2418 | } |
2419 | struct_fmt.finish() | |
2420 | } | |
2421 | } | |
2422 | } | |
2423 | ||
c30ab7b3 | 2424 | AggregateKind::Closure(def_id, _) => ty::tls::with(|tcx| { |
532ac7d7 | 2425 | if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { |
041b39d2 | 2426 | let name = if tcx.sess.opts.debugging_opts.span_free_formats { |
532ac7d7 | 2427 | format!("[closure@{:?}]", hir_id) |
041b39d2 | 2428 | } else { |
dc9dc135 | 2429 | format!("[closure@{:?}]", tcx.hir().span(hir_id)) |
041b39d2 | 2430 | }; |
9cc50fc6 SL |
2431 | let mut struct_fmt = fmt.debug_struct(&name); |
2432 | ||
48663c56 | 2433 | if let Some(upvars) = tcx.upvars(def_id) { |
dc9dc135 XL |
2434 | for (&var_id, place) in upvars.keys().zip(places) { |
2435 | let var_name = tcx.hir().name(var_id); | |
ff7c6d11 | 2436 | struct_fmt.field(&var_name.as_str(), place); |
9cc50fc6 | 2437 | } |
48663c56 | 2438 | } |
9cc50fc6 SL |
2439 | |
2440 | struct_fmt.finish() | |
2441 | } else { | |
2442 | write!(fmt, "[closure]") | |
2443 | } | |
2444 | }), | |
ea8adc8c XL |
2445 | |
2446 | AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| { | |
532ac7d7 | 2447 | if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { |
416331ca | 2448 | let name = format!("[generator@{:?}]", tcx.hir().span(hir_id)); |
ea8adc8c XL |
2449 | let mut struct_fmt = fmt.debug_struct(&name); |
2450 | ||
48663c56 | 2451 | if let Some(upvars) = tcx.upvars(def_id) { |
dc9dc135 XL |
2452 | for (&var_id, place) in upvars.keys().zip(places) { |
2453 | let var_name = tcx.hir().name(var_id); | |
ff7c6d11 | 2454 | struct_fmt.field(&var_name.as_str(), place); |
ea8adc8c | 2455 | } |
48663c56 | 2456 | } |
ea8adc8c XL |
2457 | |
2458 | struct_fmt.finish() | |
2459 | } else { | |
2460 | write!(fmt, "[generator]") | |
2461 | } | |
2462 | }), | |
9cc50fc6 SL |
2463 | } |
2464 | } | |
e9174d1e SL |
2465 | } |
2466 | } | |
2467 | } | |
2468 | ||
2469 | /////////////////////////////////////////////////////////////////////////// | |
7453a54e SL |
2470 | /// Constants |
2471 | /// | |
2472 | /// Two constants are equal if they are the same constant. Note that | |
2473 | /// this does not necessarily mean that they are "==" in Rust -- in | |
2474 | /// particular one must be wary of `NaN`! | |
e9174d1e | 2475 | |
532ac7d7 | 2476 | #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] |
b039eaaf SL |
2477 | pub struct Constant<'tcx> { |
2478 | pub span: Span, | |
2479 | pub ty: Ty<'tcx>, | |
b7449926 XL |
2480 | |
2481 | /// Optional user-given type: for something like | |
2482 | /// `collect::<Vec<_>>`, this would be present and would | |
2483 | /// indicate that `Vec<_>` was explicitly specified. | |
2484 | /// | |
2485 | /// Needed for NLL to impose user-given type constraints. | |
0731742a | 2486 | pub user_ty: Option<UserTypeAnnotationIndex>, |
b7449926 | 2487 | |
532ac7d7 | 2488 | pub literal: &'tcx ty::Const<'tcx>, |
0bf4aa26 XL |
2489 | } |
2490 | ||
2491 | /// A collection of projections into user types. | |
2492 | /// | |
2493 | /// They are projections because a binding can occur a part of a | |
2494 | /// parent pattern that has been ascribed a type. | |
2495 | /// | |
2496 | /// Its a collection because there can be multiple type ascriptions on | |
2497 | /// the path from the root of the pattern down to the binding itself. | |
2498 | /// | |
2499 | /// An example: | |
2500 | /// | |
2501 | /// ```rust | |
2502 | /// struct S<'a>((i32, &'a str), String); | |
2503 | /// let S((_, w): (i32, &'static str), _): S = ...; | |
2504 | /// // ------ ^^^^^^^^^^^^^^^^^^^ (1) | |
2505 | /// // --------------------------------- ^ (2) | |
2506 | /// ``` | |
2507 | /// | |
2508 | /// The highlights labelled `(1)` show the subpattern `(_, w)` being | |
2509 | /// ascribed the type `(i32, &'static str)`. | |
2510 | /// | |
2511 | /// The highlights labelled `(2)` show the whole pattern being | |
2512 | /// ascribed the type `S`. | |
2513 | /// | |
2514 | /// In this example, when we descend to `w`, we will have built up the | |
2515 | /// following two projected types: | |
2516 | /// | |
2517 | /// * base: `S`, projection: `(base.0).1` | |
2518 | /// * base: `(i32, &'static str)`, projection: `base.1` | |
2519 | /// | |
2520 | /// The first will lead to the constraint `w: &'1 str` (for some | |
2521 | /// inferred region `'1`). The second will lead to the constraint `w: | |
2522 | /// &'static str`. | |
532ac7d7 XL |
2523 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] |
2524 | pub struct UserTypeProjections { | |
2525 | pub(crate) contents: Vec<(UserTypeProjection, Span)>, | |
0bf4aa26 XL |
2526 | } |
2527 | ||
2528 | BraceStructTypeFoldableImpl! { | |
532ac7d7 | 2529 | impl<'tcx> TypeFoldable<'tcx> for UserTypeProjections { |
0bf4aa26 XL |
2530 | contents |
2531 | } | |
2532 | } | |
2533 | ||
532ac7d7 | 2534 | impl<'tcx> UserTypeProjections { |
0bf4aa26 XL |
2535 | pub fn none() -> Self { |
2536 | UserTypeProjections { contents: vec![] } | |
2537 | } | |
2538 | ||
416331ca | 2539 | pub fn from_projections(projs: impl Iterator<Item = (UserTypeProjection, Span)>) -> Self { |
0bf4aa26 XL |
2540 | UserTypeProjections { contents: projs.collect() } |
2541 | } | |
2542 | ||
416331ca | 2543 | pub fn projections_and_spans(&self) -> impl Iterator<Item = &(UserTypeProjection, Span)> { |
0bf4aa26 XL |
2544 | self.contents.iter() |
2545 | } | |
2546 | ||
416331ca | 2547 | pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> { |
0bf4aa26 XL |
2548 | self.contents.iter().map(|&(ref user_type, _span)| user_type) |
2549 | } | |
0731742a | 2550 | |
416331ca | 2551 | pub fn push_projection(mut self, user_ty: &UserTypeProjection, span: Span) -> Self { |
0731742a XL |
2552 | self.contents.push((user_ty.clone(), span)); |
2553 | self | |
2554 | } | |
2555 | ||
2556 | fn map_projections( | |
2557 | mut self, | |
416331ca | 2558 | mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection, |
0731742a XL |
2559 | ) -> Self { |
2560 | self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect(); | |
2561 | self | |
2562 | } | |
2563 | ||
2564 | pub fn index(self) -> Self { | |
2565 | self.map_projections(|pat_ty_proj| pat_ty_proj.index()) | |
2566 | } | |
2567 | ||
2568 | pub fn subslice(self, from: u32, to: u32) -> Self { | |
2569 | self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) | |
2570 | } | |
2571 | ||
2572 | pub fn deref(self) -> Self { | |
2573 | self.map_projections(|pat_ty_proj| pat_ty_proj.deref()) | |
2574 | } | |
2575 | ||
2576 | pub fn leaf(self, field: Field) -> Self { | |
2577 | self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field)) | |
2578 | } | |
2579 | ||
416331ca | 2580 | pub fn variant(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx, field: Field) -> Self { |
0731742a XL |
2581 | self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field)) |
2582 | } | |
0bf4aa26 XL |
2583 | } |
2584 | ||
2585 | /// Encodes the effect of a user-supplied type annotation on the | |
2586 | /// subcomponents of a pattern. The effect is determined by applying the | |
2587 | /// given list of proejctions to some underlying base type. Often, | |
2588 | /// the projection element list `projs` is empty, in which case this | |
2589 | /// directly encodes a type in `base`. But in the case of complex patterns with | |
2590 | /// subpatterns and bindings, we want to apply only a *part* of the type to a variable, | |
2591 | /// in which case the `projs` vector is used. | |
2592 | /// | |
2593 | /// Examples: | |
2594 | /// | |
2595 | /// * `let x: T = ...` -- here, the `projs` vector is empty. | |
2596 | /// | |
2597 | /// * `let (x, _): T = ...` -- here, the `projs` vector would contain | |
2598 | /// `field[0]` (aka `.0`), indicating that the type of `s` is | |
2599 | /// determined by finding the type of the `.0` field from `T`. | |
532ac7d7 XL |
2600 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] |
2601 | pub struct UserTypeProjection { | |
0731742a | 2602 | pub base: UserTypeAnnotationIndex, |
dc9dc135 | 2603 | pub projs: Vec<ProjectionKind>, |
0bf4aa26 XL |
2604 | } |
2605 | ||
416331ca | 2606 | impl Copy for ProjectionKind {} |
0bf4aa26 | 2607 | |
532ac7d7 | 2608 | impl UserTypeProjection { |
0731742a XL |
2609 | pub(crate) fn index(mut self) -> Self { |
2610 | self.projs.push(ProjectionElem::Index(())); | |
2611 | self | |
2612 | } | |
2613 | ||
2614 | pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self { | |
2615 | self.projs.push(ProjectionElem::Subslice { from, to }); | |
2616 | self | |
2617 | } | |
2618 | ||
2619 | pub(crate) fn deref(mut self) -> Self { | |
2620 | self.projs.push(ProjectionElem::Deref); | |
2621 | self | |
2622 | } | |
2623 | ||
2624 | pub(crate) fn leaf(mut self, field: Field) -> Self { | |
2625 | self.projs.push(ProjectionElem::Field(field, ())); | |
2626 | self | |
2627 | } | |
2628 | ||
2629 | pub(crate) fn variant( | |
2630 | mut self, | |
2631 | adt_def: &'tcx AdtDef, | |
2632 | variant_index: VariantIdx, | |
2633 | field: Field, | |
2634 | ) -> Self { | |
532ac7d7 XL |
2635 | self.projs.push(ProjectionElem::Downcast( |
2636 | Some(adt_def.variants[variant_index].ident.name), | |
416331ca XL |
2637 | variant_index, |
2638 | )); | |
0731742a XL |
2639 | self.projs.push(ProjectionElem::Field(field, ())); |
2640 | self | |
2641 | } | |
2642 | } | |
2643 | ||
532ac7d7 | 2644 | CloneTypeFoldableAndLiftImpls! { ProjectionKind, } |
0bf4aa26 | 2645 | |
532ac7d7 | 2646 | impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { |
dc9dc135 | 2647 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { |
9fa01778 | 2648 | use crate::mir::ProjectionElem::*; |
0bf4aa26 XL |
2649 | |
2650 | let base = self.base.fold_with(folder); | |
416331ca XL |
2651 | let projs: Vec<_> = self |
2652 | .projs | |
0bf4aa26 | 2653 | .iter() |
416331ca XL |
2654 | .map(|elem| match elem { |
2655 | Deref => Deref, | |
2656 | Field(f, ()) => Field(f.clone(), ()), | |
2657 | Index(()) => Index(()), | |
2658 | elem => elem.clone(), | |
2659 | }) | |
0bf4aa26 XL |
2660 | .collect(); |
2661 | ||
2662 | UserTypeProjection { base, projs } | |
2663 | } | |
2664 | ||
2665 | fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { | |
2666 | self.base.visit_with(visitor) | |
2667 | // Note: there's nothing in `self.proj` to visit. | |
2668 | } | |
2669 | } | |
2670 | ||
b7449926 XL |
2671 | newtype_index! { |
2672 | pub struct Promoted { | |
532ac7d7 | 2673 | derive [HashStable] |
b7449926 XL |
2674 | DEBUG_FORMAT = "promoted[{}]" |
2675 | } | |
2676 | } | |
abe05a73 | 2677 | |
9cc50fc6 | 2678 | impl<'tcx> Debug for Constant<'tcx> { |
0bf4aa26 | 2679 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
dc9dc135 | 2680 | write!(fmt, "{}", self) |
9cc50fc6 SL |
2681 | } |
2682 | } | |
2683 | ||
dc9dc135 XL |
2684 | impl<'tcx> Display for Constant<'tcx> { |
2685 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { | |
2686 | write!(fmt, "const ")?; | |
2687 | write!(fmt, "{}", self.literal) | |
2688 | } | |
9cc50fc6 | 2689 | } |
3157f602 | 2690 | |
dc9dc135 | 2691 | impl<'tcx> graph::DirectedGraph for Body<'tcx> { |
3157f602 | 2692 | type Node = BasicBlock; |
8faf50e0 | 2693 | } |
3157f602 | 2694 | |
dc9dc135 | 2695 | impl<'tcx> graph::WithNumNodes for Body<'tcx> { |
94b46f34 XL |
2696 | fn num_nodes(&self) -> usize { |
2697 | self.basic_blocks.len() | |
2698 | } | |
8faf50e0 | 2699 | } |
3157f602 | 2700 | |
dc9dc135 | 2701 | impl<'tcx> graph::WithStartNode for Body<'tcx> { |
94b46f34 XL |
2702 | fn start_node(&self) -> Self::Node { |
2703 | START_BLOCK | |
2704 | } | |
8faf50e0 | 2705 | } |
3157f602 | 2706 | |
dc9dc135 | 2707 | impl<'tcx> graph::WithPredecessors for Body<'tcx> { |
416331ca XL |
2708 | fn predecessors( |
2709 | &self, | |
94b46f34 | 2710 | node: Self::Node, |
416331ca | 2711 | ) -> <Self as GraphPredecessors<'_>>::Iter { |
3157f602 XL |
2712 | self.predecessors_for(node).clone().into_iter() |
2713 | } | |
8faf50e0 XL |
2714 | } |
2715 | ||
dc9dc135 | 2716 | impl<'tcx> graph::WithSuccessors for Body<'tcx> { |
416331ca XL |
2717 | fn successors( |
2718 | &self, | |
94b46f34 | 2719 | node: Self::Node, |
416331ca | 2720 | ) -> <Self as GraphSuccessors<'_>>::Iter { |
83c7162d | 2721 | self.basic_blocks[node].terminator().successors().cloned() |
3157f602 XL |
2722 | } |
2723 | } | |
2724 | ||
dc9dc135 | 2725 | impl<'a, 'b> graph::GraphPredecessors<'b> for Body<'a> { |
3157f602 XL |
2726 | type Item = BasicBlock; |
2727 | type Iter = IntoIter<BasicBlock>; | |
2728 | } | |
2729 | ||
dc9dc135 | 2730 | impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { |
3157f602 | 2731 | type Item = BasicBlock; |
83c7162d | 2732 | type Iter = iter::Cloned<Successors<'b>>; |
3157f602 | 2733 | } |
9e0c209e | 2734 | |
532ac7d7 | 2735 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)] |
9e0c209e SL |
2736 | pub struct Location { |
2737 | /// the location is within this block | |
2738 | pub block: BasicBlock, | |
2739 | ||
2c00a5a8 | 2740 | /// the location is the start of the statement; or, if `statement_index` |
9e0c209e SL |
2741 | /// == num-statements, then the start of the terminator. |
2742 | pub statement_index: usize, | |
2743 | } | |
2744 | ||
2745 | impl fmt::Debug for Location { | |
0bf4aa26 | 2746 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
9e0c209e SL |
2747 | write!(fmt, "{:?}[{}]", self.block, self.statement_index) |
2748 | } | |
2749 | } | |
2750 | ||
2751 | impl Location { | |
416331ca | 2752 | pub const START: Location = Location { block: START_BLOCK, statement_index: 0 }; |
83c7162d | 2753 | |
abe05a73 XL |
2754 | /// Returns the location immediately after this one within the enclosing block. |
2755 | /// | |
2756 | /// Note that if this location represents a terminator, then the | |
2757 | /// resulting location would be out of bounds and invalid. | |
2758 | pub fn successor_within_block(&self) -> Location { | |
416331ca | 2759 | Location { block: self.block, statement_index: self.statement_index + 1 } |
abe05a73 XL |
2760 | } |
2761 | ||
a1dfa0c6 | 2762 | /// Returns `true` if `other` is earlier in the control flow graph than `self`. |
dc9dc135 | 2763 | pub fn is_predecessor_of<'tcx>(&self, other: Location, body: &Body<'tcx>) -> bool { |
a1dfa0c6 XL |
2764 | // If we are in the same block as the other location and are an earlier statement |
2765 | // then we are a predecessor of `other`. | |
2766 | if self.block == other.block && self.statement_index < other.statement_index { | |
2767 | return true; | |
2768 | } | |
2769 | ||
2770 | // If we're in another block, then we want to check that block is a predecessor of `other`. | |
dc9dc135 | 2771 | let mut queue: Vec<BasicBlock> = body.predecessors_for(other.block).clone(); |
a1dfa0c6 XL |
2772 | let mut visited = FxHashSet::default(); |
2773 | ||
2774 | while let Some(block) = queue.pop() { | |
2775 | // If we haven't visited this block before, then make sure we visit it's predecessors. | |
2776 | if visited.insert(block) { | |
dc9dc135 | 2777 | queue.append(&mut body.predecessors_for(block).clone()); |
a1dfa0c6 XL |
2778 | } else { |
2779 | continue; | |
2780 | } | |
2781 | ||
2782 | // If we found the block that `self` is in, then we are a predecessor of `other` (since | |
2783 | // we found that block by looking at the predecessors of `other`). | |
2784 | if self.block == block { | |
2785 | return true; | |
2786 | } | |
2787 | } | |
2788 | ||
2789 | false | |
2790 | } | |
2791 | ||
83c7162d | 2792 | pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool { |
9e0c209e SL |
2793 | if self.block == other.block { |
2794 | self.statement_index <= other.statement_index | |
2795 | } else { | |
2796 | dominators.is_dominated_by(other.block, self.block) | |
2797 | } | |
2798 | } | |
2799 | } | |
8bb4bdeb | 2800 | |
532ac7d7 | 2801 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] |
ff7c6d11 XL |
2802 | pub enum UnsafetyViolationKind { |
2803 | General, | |
9fa01778 | 2804 | /// Permitted in const fn and regular fns. |
0731742a | 2805 | GeneralAndConstFn, |
532ac7d7 XL |
2806 | ExternStatic(hir::HirId), |
2807 | BorrowPacked(hir::HirId), | |
ff7c6d11 XL |
2808 | } |
2809 | ||
532ac7d7 | 2810 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] |
ea8adc8c XL |
2811 | pub struct UnsafetyViolation { |
2812 | pub source_info: SourceInfo, | |
ff7c6d11 | 2813 | pub description: InternedString, |
8faf50e0 | 2814 | pub details: InternedString, |
ff7c6d11 | 2815 | pub kind: UnsafetyViolationKind, |
ea8adc8c XL |
2816 | } |
2817 | ||
532ac7d7 | 2818 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] |
ea8adc8c XL |
2819 | pub struct UnsafetyCheckResult { |
2820 | /// Violations that are propagated *upwards* from this function | |
0531ce1d | 2821 | pub violations: Lrc<[UnsafetyViolation]>, |
ea8adc8c XL |
2822 | /// unsafe blocks in this function, along with whether they are used. This is |
2823 | /// used for the "unused_unsafe" lint. | |
532ac7d7 | 2824 | pub unsafe_blocks: Lrc<[(hir::HirId, bool)]>, |
ea8adc8c XL |
2825 | } |
2826 | ||
48663c56 XL |
2827 | newtype_index! { |
2828 | pub struct GeneratorSavedLocal { | |
2829 | derive [HashStable] | |
2830 | DEBUG_FORMAT = "_{}", | |
2831 | } | |
2832 | } | |
2833 | ||
ea8adc8c | 2834 | /// The layout of generator state |
532ac7d7 | 2835 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
ea8adc8c | 2836 | pub struct GeneratorLayout<'tcx> { |
48663c56 XL |
2837 | /// The type of every local stored inside the generator. |
2838 | pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>, | |
2839 | ||
2840 | /// Which of the above fields are in each variant. Note that one field may | |
2841 | /// be stored in multiple variants. | |
2842 | pub variant_fields: IndexVec<VariantIdx, IndexVec<Field, GeneratorSavedLocal>>, | |
2843 | ||
dc9dc135 XL |
2844 | /// Which saved locals are storage-live at the same time. Locals that do not |
2845 | /// have conflicts with each other are allowed to overlap in the computed | |
2846 | /// layout. | |
2847 | pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>, | |
2848 | ||
48663c56 XL |
2849 | /// Names and scopes of all the stored generator locals. |
2850 | /// NOTE(tmandry) This is *strictly* a temporary hack for codegen | |
2851 | /// debuginfo generation, and will be removed at some point. | |
2852 | /// Do **NOT** use it for anything else, local information should not be | |
2853 | /// in the MIR, please rely on local crate HIR or other side-channels. | |
2854 | pub __local_debuginfo_codegen_only_do_not_use: IndexVec<GeneratorSavedLocal, LocalDecl<'tcx>>, | |
ea8adc8c | 2855 | } |
8bb4bdeb | 2856 | |
532ac7d7 | 2857 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
dc9dc135 XL |
2858 | pub struct BorrowCheckResult<'tcx> { |
2859 | pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>, | |
83c7162d XL |
2860 | pub used_mut_upvars: SmallVec<[Field; 8]>, |
2861 | } | |
2862 | ||
ff7c6d11 XL |
2863 | /// After we borrow check a closure, we are left with various |
2864 | /// requirements that we have inferred between the free regions that | |
9fa01778 | 2865 | /// appear in the closure's signature or on its field types. These |
ff7c6d11 XL |
2866 | /// requirements are then verified and proved by the closure's |
2867 | /// creating function. This struct encodes those requirements. | |
2868 | /// | |
2869 | /// The requirements are listed as being between various | |
2870 | /// `RegionVid`. The 0th region refers to `'static`; subsequent region | |
2871 | /// vids refer to the free regions that appear in the closure (or | |
2872 | /// generator's) type, in order of appearance. (This numbering is | |
2873 | /// actually defined by the `UniversalRegions` struct in the NLL | |
2874 | /// region checker. See for example | |
2875 | /// `UniversalRegions::closure_mapping`.) Note that we treat the free | |
2876 | /// regions in the closure's type "as if" they were erased, so their | |
2877 | /// precise identity is not important, only their position. | |
2878 | /// | |
2879 | /// Example: If type check produces a closure with the closure substs: | |
2880 | /// | |
2881 | /// ```text | |
2882 | /// ClosureSubsts = [ | |
2883 | /// i8, // the "closure kind" | |
2884 | /// for<'x> fn(&'a &'x u32) -> &'x u32, // the "closure signature" | |
2885 | /// &'a String, // some upvar | |
2886 | /// ] | |
2887 | /// ``` | |
2888 | /// | |
2889 | /// here, there is one unique free region (`'a`) but it appears | |
0531ce1d | 2890 | /// twice. We would "renumber" each occurrence to a unique vid, as follows: |
ff7c6d11 XL |
2891 | /// |
2892 | /// ```text | |
2893 | /// ClosureSubsts = [ | |
2894 | /// i8, // the "closure kind" | |
2895 | /// for<'x> fn(&'1 &'x u32) -> &'x u32, // the "closure signature" | |
2896 | /// &'2 String, // some upvar | |
2897 | /// ] | |
2898 | /// ``` | |
2899 | /// | |
2900 | /// Now the code might impose a requirement like `'1: '2`. When an | |
2901 | /// instance of the closure is created, the corresponding free regions | |
2902 | /// can be extracted from its type and constrained to have the given | |
2903 | /// outlives relationship. | |
2904 | /// | |
2905 | /// In some cases, we have to record outlives requirements between | |
2906 | /// types and regions as well. In that case, if those types include | |
2907 | /// any regions, those regions are recorded as `ReClosureBound` | |
2908 | /// instances assigned one of these same indices. Those regions will | |
2909 | /// be substituted away by the creator. We use `ReClosureBound` in | |
2910 | /// that case because the regions must be allocated in the global | |
2911 | /// TyCtxt, and hence we cannot use `ReVar` (which is what we use | |
2912 | /// internally within the rest of the NLL code). | |
532ac7d7 | 2913 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
dc9dc135 | 2914 | pub struct ClosureRegionRequirements<'tcx> { |
9fa01778 | 2915 | /// The number of external regions defined on the closure. In our |
ff7c6d11 XL |
2916 | /// example above, it would be 3 -- one for `'static`, then `'1` |
2917 | /// and `'2`. This is just used for a sanity check later on, to | |
2918 | /// make sure that the number of regions we see at the callsite | |
2919 | /// matches. | |
2920 | pub num_external_vids: usize, | |
2921 | ||
2922 | /// Requirements between the various free regions defined in | |
2923 | /// indices. | |
dc9dc135 | 2924 | pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>, |
ff7c6d11 XL |
2925 | } |
2926 | ||
2927 | /// Indicates an outlives constraint between a type or between two | |
2928 | /// free-regions declared on the closure. | |
532ac7d7 | 2929 | #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
ff7c6d11 XL |
2930 | pub struct ClosureOutlivesRequirement<'tcx> { |
2931 | // This region or type ... | |
2932 | pub subject: ClosureOutlivesSubject<'tcx>, | |
2933 | ||
0bf4aa26 | 2934 | // ... must outlive this one. |
ff7c6d11 XL |
2935 | pub outlived_free_region: ty::RegionVid, |
2936 | ||
0bf4aa26 | 2937 | // If not, report an error here ... |
ff7c6d11 | 2938 | pub blame_span: Span, |
0bf4aa26 XL |
2939 | |
2940 | // ... due to this reason. | |
2941 | pub category: ConstraintCategory, | |
2942 | } | |
2943 | ||
2944 | /// Outlives constraints can be categorized to determine whether and why they | |
2945 | /// are interesting (for error reporting). Order of variants indicates sort | |
2946 | /// order of the category, thereby influencing diagnostic output. | |
2947 | /// | |
2948 | /// See also [rustc_mir::borrow_check::nll::constraints] | |
416331ca XL |
2949 | #[derive( |
2950 | Copy, | |
2951 | Clone, | |
2952 | Debug, | |
2953 | Eq, | |
2954 | PartialEq, | |
2955 | PartialOrd, | |
2956 | Ord, | |
2957 | Hash, | |
2958 | RustcEncodable, | |
2959 | RustcDecodable, | |
2960 | HashStable, | |
2961 | )] | |
0bf4aa26 XL |
2962 | pub enum ConstraintCategory { |
2963 | Return, | |
0731742a | 2964 | Yield, |
0bf4aa26 XL |
2965 | UseAsConst, |
2966 | UseAsStatic, | |
2967 | TypeAnnotation, | |
2968 | Cast, | |
2969 | ||
2970 | /// A constraint that came from checking the body of a closure. | |
2971 | /// | |
2972 | /// We try to get the category that the closure used when reporting this. | |
2973 | ClosureBounds, | |
2974 | CallArgument, | |
2975 | CopyBound, | |
2976 | SizedBound, | |
2977 | Assignment, | |
2978 | OpaqueType, | |
2979 | ||
2980 | /// A "boring" constraint (caused by the given location) is one that | |
2981 | /// the user probably doesn't want to see described in diagnostics, | |
2982 | /// because it is kind of an artifact of the type system setup. | |
2983 | /// Example: `x = Foo { field: y }` technically creates | |
2984 | /// intermediate regions representing the "type of `Foo { field: y | |
2985 | /// }`", and data flows from `y` into those variables, but they | |
2986 | /// are not very interesting. The assignment into `x` on the other | |
2987 | /// hand might be. | |
2988 | Boring, | |
2989 | // Boring and applicable everywhere. | |
2990 | BoringNoLocation, | |
2991 | ||
2992 | /// A constraint that doesn't correspond to anything the user sees. | |
2993 | Internal, | |
ff7c6d11 XL |
2994 | } |
2995 | ||
2996 | /// The subject of a ClosureOutlivesRequirement -- that is, the thing | |
2997 | /// that must outlive some region. | |
532ac7d7 | 2998 | #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] |
ff7c6d11 XL |
2999 | pub enum ClosureOutlivesSubject<'tcx> { |
3000 | /// Subject is a type, typically a type parameter, but could also | |
3001 | /// be a projection. Indicates a requirement like `T: 'a` being | |
3002 | /// passed to the caller, where the type here is `T`. | |
3003 | /// | |
3004 | /// The type here is guaranteed not to contain any free regions at | |
3005 | /// present. | |
3006 | Ty(Ty<'tcx>), | |
3007 | ||
3008 | /// Subject is a free region from the closure. Indicates a requirement | |
3009 | /// like `'a: 'b` being passed to the caller; the region here is `'a`. | |
3010 | Region(ty::RegionVid), | |
3011 | } | |
3012 | ||
8bb4bdeb XL |
3013 | /* |
3014 | * TypeFoldable implementations for MIR types | |
dc9dc135 | 3015 | */ |
8bb4bdeb | 3016 | |
0531ce1d | 3017 | CloneTypeFoldableAndLiftImpls! { |
0bf4aa26 | 3018 | BlockTailInfo, |
a1dfa0c6 | 3019 | MirPhase, |
0531ce1d XL |
3020 | Mutability, |
3021 | SourceInfo, | |
48663c56 | 3022 | UpvarDebuginfo, |
0bf4aa26 | 3023 | FakeReadCause, |
0731742a | 3024 | RetagKind, |
94b46f34 XL |
3025 | SourceScope, |
3026 | SourceScopeData, | |
3027 | SourceScopeLocalData, | |
0731742a | 3028 | UserTypeAnnotationIndex, |
8bb4bdeb XL |
3029 | } |
3030 | ||
0531ce1d | 3031 | BraceStructTypeFoldableImpl! { |
dc9dc135 | 3032 | impl<'tcx> TypeFoldable<'tcx> for Body<'tcx> { |
a1dfa0c6 | 3033 | phase, |
0531ce1d | 3034 | basic_blocks, |
94b46f34 XL |
3035 | source_scopes, |
3036 | source_scope_local_data, | |
0531ce1d XL |
3037 | promoted, |
3038 | yield_ty, | |
3039 | generator_drop, | |
3040 | generator_layout, | |
3041 | local_decls, | |
0731742a | 3042 | user_type_annotations, |
0531ce1d | 3043 | arg_count, |
48663c56 | 3044 | __upvar_debuginfo_codegen_only_do_not_use, |
0531ce1d | 3045 | spread_arg, |
0731742a | 3046 | control_flow_destroyed, |
0531ce1d XL |
3047 | span, |
3048 | cache, | |
ea8adc8c XL |
3049 | } |
3050 | } | |
3051 | ||
0531ce1d XL |
3052 | BraceStructTypeFoldableImpl! { |
3053 | impl<'tcx> TypeFoldable<'tcx> for GeneratorLayout<'tcx> { | |
48663c56 XL |
3054 | field_tys, |
3055 | variant_fields, | |
dc9dc135 | 3056 | storage_conflicts, |
48663c56 | 3057 | __local_debuginfo_codegen_only_do_not_use, |
8bb4bdeb XL |
3058 | } |
3059 | } | |
3060 | ||
0531ce1d XL |
3061 | BraceStructTypeFoldableImpl! { |
3062 | impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> { | |
3063 | mutability, | |
3064 | is_user_variable, | |
3065 | internal, | |
3066 | ty, | |
b7449926 | 3067 | user_ty, |
0531ce1d XL |
3068 | name, |
3069 | source_info, | |
0bf4aa26 | 3070 | is_block_tail, |
94b46f34 | 3071 | visibility_scope, |
8bb4bdeb | 3072 | } |
0531ce1d | 3073 | } |
8bb4bdeb | 3074 | |
0531ce1d XL |
3075 | BraceStructTypeFoldableImpl! { |
3076 | impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> { | |
3077 | statements, | |
3078 | terminator, | |
3079 | is_cleanup, | |
8bb4bdeb XL |
3080 | } |
3081 | } | |
3082 | ||
0531ce1d XL |
3083 | BraceStructTypeFoldableImpl! { |
3084 | impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { | |
3085 | source_info, kind | |
3b2f2976 XL |
3086 | } |
3087 | } | |
3088 | ||
0531ce1d XL |
3089 | EnumTypeFoldableImpl! { |
3090 | impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> { | |
3091 | (StatementKind::Assign)(a, b), | |
0bf4aa26 | 3092 | (StatementKind::FakeRead)(cause, place), |
0531ce1d XL |
3093 | (StatementKind::SetDiscriminant) { place, variant_index }, |
3094 | (StatementKind::StorageLive)(a), | |
3095 | (StatementKind::StorageDead)(a), | |
532ac7d7 | 3096 | (StatementKind::InlineAsm)(a), |
0731742a | 3097 | (StatementKind::Retag)(kind, place), |
b7449926 | 3098 | (StatementKind::AscribeUserType)(a, v, b), |
0531ce1d | 3099 | (StatementKind::Nop), |
8bb4bdeb | 3100 | } |
0531ce1d | 3101 | } |
8bb4bdeb | 3102 | |
532ac7d7 XL |
3103 | BraceStructTypeFoldableImpl! { |
3104 | impl<'tcx> TypeFoldable<'tcx> for InlineAsm<'tcx> { | |
3105 | asm, | |
3106 | outputs, | |
3107 | inputs, | |
3108 | } | |
3109 | } | |
3110 | ||
0531ce1d XL |
3111 | EnumTypeFoldableImpl! { |
3112 | impl<'tcx, T> TypeFoldable<'tcx> for ClearCrossCrate<T> { | |
3113 | (ClearCrossCrate::Clear), | |
3114 | (ClearCrossCrate::Set)(a), | |
3115 | } where T: TypeFoldable<'tcx> | |
8bb4bdeb XL |
3116 | } |
3117 | ||
3118 | impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { | |
dc9dc135 | 3119 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { |
9fa01778 | 3120 | use crate::mir::TerminatorKind::*; |
8bb4bdeb XL |
3121 | |
3122 | let kind = match self.kind { | |
a1dfa0c6 | 3123 | Goto { target } => Goto { target }, |
416331ca | 3124 | SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { |
8bb4bdeb XL |
3125 | discr: discr.fold_with(folder), |
3126 | switch_ty: switch_ty.fold_with(folder), | |
3127 | values: values.clone(), | |
94b46f34 | 3128 | targets: targets.clone(), |
8bb4bdeb | 3129 | }, |
416331ca XL |
3130 | Drop { ref location, target, unwind } => { |
3131 | Drop { location: location.fold_with(folder), target, unwind } | |
3132 | } | |
3133 | DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { | |
8bb4bdeb XL |
3134 | location: location.fold_with(folder), |
3135 | value: value.fold_with(folder), | |
041b39d2 XL |
3136 | target, |
3137 | unwind, | |
8bb4bdeb | 3138 | }, |
416331ca XL |
3139 | Yield { ref value, resume, drop } => { |
3140 | Yield { value: value.fold_with(folder), resume: resume, drop: drop } | |
3141 | } | |
3142 | Call { ref func, ref args, ref destination, cleanup, from_hir_call } => { | |
3143 | let dest = | |
3144 | destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest)); | |
8bb4bdeb XL |
3145 | |
3146 | Call { | |
3147 | func: func.fold_with(folder), | |
3148 | args: args.fold_with(folder), | |
3149 | destination: dest, | |
041b39d2 | 3150 | cleanup, |
0bf4aa26 | 3151 | from_hir_call, |
8bb4bdeb | 3152 | } |
94b46f34 | 3153 | } |
416331ca XL |
3154 | Assert { ref cond, expected, ref msg, target, cleanup } => { |
3155 | use PanicInfo::*; | |
3156 | let msg = match msg { | |
3157 | BoundsCheck { ref len, ref index } => | |
3158 | BoundsCheck { | |
3159 | len: len.fold_with(folder), | |
3160 | index: index.fold_with(folder), | |
3161 | }, | |
3162 | Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero | | |
3163 | GeneratorResumedAfterReturn | GeneratorResumedAfterPanic => | |
3164 | msg.clone(), | |
8bb4bdeb | 3165 | }; |
416331ca | 3166 | Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup } |
94b46f34 | 3167 | } |
ea8adc8c | 3168 | GeneratorDrop => GeneratorDrop, |
8bb4bdeb | 3169 | Resume => Resume, |
ff7c6d11 | 3170 | Abort => Abort, |
8bb4bdeb XL |
3171 | Return => Return, |
3172 | Unreachable => Unreachable, | |
416331ca XL |
3173 | FalseEdges { real_target, imaginary_target } => { |
3174 | FalseEdges { real_target, imaginary_target } | |
3175 | } | |
3176 | FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, | |
8bb4bdeb | 3177 | }; |
416331ca | 3178 | Terminator { source_info: self.source_info, kind } |
8bb4bdeb XL |
3179 | } |
3180 | ||
3181 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
9fa01778 | 3182 | use crate::mir::TerminatorKind::*; |
8bb4bdeb XL |
3183 | |
3184 | match self.kind { | |
416331ca XL |
3185 | SwitchInt { ref discr, switch_ty, .. } => { |
3186 | discr.visit_with(visitor) || switch_ty.visit_with(visitor) | |
3187 | } | |
94b46f34 | 3188 | Drop { ref location, .. } => location.visit_with(visitor), |
416331ca XL |
3189 | DropAndReplace { ref location, ref value, .. } => { |
3190 | location.visit_with(visitor) || value.visit_with(visitor) | |
3191 | } | |
94b46f34 | 3192 | Yield { ref value, .. } => value.visit_with(visitor), |
416331ca | 3193 | Call { ref func, ref args, ref destination, .. } => { |
8bb4bdeb XL |
3194 | let dest = if let Some((ref loc, _)) = *destination { |
3195 | loc.visit_with(visitor) | |
94b46f34 XL |
3196 | } else { |
3197 | false | |
3198 | }; | |
8bb4bdeb | 3199 | dest || func.visit_with(visitor) || args.visit_with(visitor) |
94b46f34 | 3200 | } |
416331ca | 3201 | Assert { ref cond, ref msg, .. } => { |
8bb4bdeb | 3202 | if cond.visit_with(visitor) { |
416331ca XL |
3203 | use PanicInfo::*; |
3204 | match msg { | |
3205 | BoundsCheck { ref len, ref index } => | |
3206 | len.visit_with(visitor) || index.visit_with(visitor), | |
3207 | Panic { .. } | Overflow(_) | OverflowNeg | | |
3208 | DivisionByZero | RemainderByZero | | |
3209 | GeneratorResumedAfterReturn | GeneratorResumedAfterPanic => | |
3210 | false | |
8bb4bdeb XL |
3211 | } |
3212 | } else { | |
3213 | false | |
3214 | } | |
94b46f34 XL |
3215 | } |
3216 | Goto { .. } | |
3217 | | Resume | |
3218 | | Abort | |
3219 | | Return | |
3220 | | GeneratorDrop | |
3221 | | Unreachable | |
3222 | | FalseEdges { .. } | |
3223 | | FalseUnwind { .. } => false, | |
8bb4bdeb XL |
3224 | } |
3225 | } | |
3226 | } | |
3227 | ||
ff7c6d11 | 3228 | impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { |
dc9dc135 | 3229 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { |
416331ca XL |
3230 | Place { |
3231 | base: self.base.clone(), | |
3232 | projection: self.projection.fold_with(folder), | |
8bb4bdeb XL |
3233 | } |
3234 | } | |
3235 | ||
3236 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
416331ca | 3237 | self.projection.visit_with(visitor) |
8bb4bdeb XL |
3238 | } |
3239 | } | |
3240 | ||
3241 | impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { | |
dc9dc135 | 3242 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { |
9fa01778 | 3243 | use crate::mir::Rvalue::*; |
8bb4bdeb XL |
3244 | match *self { |
3245 | Use(ref op) => Use(op.fold_with(folder)), | |
3246 | Repeat(ref op, len) => Repeat(op.fold_with(folder), len), | |
94b46f34 XL |
3247 | Ref(region, bk, ref place) => { |
3248 | Ref(region.fold_with(folder), bk, place.fold_with(folder)) | |
3249 | } | |
ff7c6d11 | 3250 | Len(ref place) => Len(place.fold_with(folder)), |
8bb4bdeb | 3251 | Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), |
94b46f34 XL |
3252 | BinaryOp(op, ref rhs, ref lhs) => { |
3253 | BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) | |
3254 | } | |
3255 | CheckedBinaryOp(op, ref rhs, ref lhs) => { | |
3256 | CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) | |
3257 | } | |
8bb4bdeb | 3258 | UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), |
ff7c6d11 | 3259 | Discriminant(ref place) => Discriminant(place.fold_with(folder)), |
7cac9316 | 3260 | NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), |
8bb4bdeb | 3261 | Aggregate(ref kind, ref fields) => { |
cc61c64b | 3262 | let kind = box match **kind { |
8bb4bdeb XL |
3263 | AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), |
3264 | AggregateKind::Tuple => AggregateKind::Tuple, | |
b7449926 XL |
3265 | AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt( |
3266 | def, | |
3267 | v, | |
3268 | substs.fold_with(folder), | |
3269 | user_ty.fold_with(folder), | |
3270 | n, | |
3271 | ), | |
94b46f34 XL |
3272 | AggregateKind::Closure(id, substs) => { |
3273 | AggregateKind::Closure(id, substs.fold_with(folder)) | |
3274 | } | |
3275 | AggregateKind::Generator(id, substs, movablity) => { | |
3276 | AggregateKind::Generator(id, substs.fold_with(folder), movablity) | |
3277 | } | |
8bb4bdeb XL |
3278 | }; |
3279 | Aggregate(kind, fields.fold_with(folder)) | |
3280 | } | |
3281 | } | |
3282 | } | |
3283 | ||
3284 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
9fa01778 | 3285 | use crate::mir::Rvalue::*; |
8bb4bdeb XL |
3286 | match *self { |
3287 | Use(ref op) => op.visit_with(visitor), | |
3288 | Repeat(ref op, _) => op.visit_with(visitor), | |
ff7c6d11 XL |
3289 | Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor), |
3290 | Len(ref place) => place.visit_with(visitor), | |
8bb4bdeb | 3291 | Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), |
94b46f34 XL |
3292 | BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => { |
3293 | rhs.visit_with(visitor) || lhs.visit_with(visitor) | |
3294 | } | |
8bb4bdeb | 3295 | UnaryOp(_, ref val) => val.visit_with(visitor), |
ff7c6d11 | 3296 | Discriminant(ref place) => place.visit_with(visitor), |
7cac9316 | 3297 | NullaryOp(_, ty) => ty.visit_with(visitor), |
8bb4bdeb | 3298 | Aggregate(ref kind, ref fields) => { |
cc61c64b | 3299 | (match **kind { |
8bb4bdeb XL |
3300 | AggregateKind::Array(ty) => ty.visit_with(visitor), |
3301 | AggregateKind::Tuple => false, | |
b7449926 XL |
3302 | AggregateKind::Adt(_, _, substs, user_ty, _) => { |
3303 | substs.visit_with(visitor) || user_ty.visit_with(visitor) | |
3304 | } | |
ea8adc8c | 3305 | AggregateKind::Closure(_, substs) => substs.visit_with(visitor), |
94b46f34 | 3306 | AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor), |
8bb4bdeb XL |
3307 | }) || fields.visit_with(visitor) |
3308 | } | |
3309 | } | |
3310 | } | |
3311 | } | |
3312 | ||
3313 | impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { | |
dc9dc135 | 3314 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { |
8bb4bdeb | 3315 | match *self { |
ff7c6d11 XL |
3316 | Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)), |
3317 | Operand::Move(ref place) => Operand::Move(place.fold_with(folder)), | |
8bb4bdeb XL |
3318 | Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), |
3319 | } | |
3320 | } | |
3321 | ||
3322 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
3323 | match *self { | |
94b46f34 XL |
3324 | Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), |
3325 | Operand::Constant(ref c) => c.visit_with(visitor), | |
8bb4bdeb XL |
3326 | } |
3327 | } | |
3328 | } | |
3329 | ||
dc9dc135 XL |
3330 | impl<'tcx> TypeFoldable<'tcx> for Projection<'tcx> { |
3331 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
9fa01778 | 3332 | use crate::mir::ProjectionElem::*; |
8bb4bdeb XL |
3333 | |
3334 | let base = self.base.fold_with(folder); | |
3335 | let elem = match self.elem { | |
3336 | Deref => Deref, | |
3b2f2976 | 3337 | Field(f, ref ty) => Field(f, ty.fold_with(folder)), |
8bb4bdeb | 3338 | Index(ref v) => Index(v.fold_with(folder)), |
94b46f34 | 3339 | ref elem => elem.clone(), |
8bb4bdeb XL |
3340 | }; |
3341 | ||
94b46f34 | 3342 | Projection { base, elem } |
8bb4bdeb XL |
3343 | } |
3344 | ||
3345 | fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { | |
9fa01778 | 3346 | use crate::mir::ProjectionElem::*; |
8bb4bdeb | 3347 | |
416331ca XL |
3348 | self.base.visit_with(visitor) |
3349 | || match self.elem { | |
3350 | Field(_, ref ty) => ty.visit_with(visitor), | |
3351 | Index(ref v) => v.visit_with(visitor), | |
3352 | _ => false, | |
3353 | } | |
8bb4bdeb XL |
3354 | } |
3355 | } | |
3356 | ||
0531ce1d | 3357 | impl<'tcx> TypeFoldable<'tcx> for Field { |
dc9dc135 | 3358 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { |
0531ce1d XL |
3359 | *self |
3360 | } | |
3361 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { | |
3362 | false | |
3363 | } | |
3364 | } | |
3365 | ||
48663c56 | 3366 | impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { |
dc9dc135 | 3367 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { |
48663c56 XL |
3368 | *self |
3369 | } | |
3370 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { | |
3371 | false | |
3372 | } | |
3373 | } | |
3374 | ||
dc9dc135 XL |
3375 | impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> { |
3376 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { | |
3377 | self.clone() | |
3378 | } | |
3379 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { | |
3380 | false | |
3381 | } | |
3382 | } | |
3383 | ||
8bb4bdeb | 3384 | impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { |
dc9dc135 | 3385 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { |
8bb4bdeb XL |
3386 | Constant { |
3387 | span: self.span.clone(), | |
3388 | ty: self.ty.fold_with(folder), | |
b7449926 | 3389 | user_ty: self.user_ty.fold_with(folder), |
94b46f34 | 3390 | literal: self.literal.fold_with(folder), |
8bb4bdeb XL |
3391 | } |
3392 | } | |
3393 | fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { | |
3394 | self.ty.visit_with(visitor) || self.literal.visit_with(visitor) | |
3395 | } | |
3396 | } |