]>
Commit | Line | Data |
---|---|---|
ba9703b0 | 1 | //! MIR datatypes and passes. See the [rustc dev guide] for more info. |
ff7c6d11 | 2 | //! |
ba9703b0 | 3 | //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html |
7cac9316 | 4 | |
3dfed10e XL |
5 | use crate::mir::coverage::{CodeRegion, CoverageKind}; |
6 | use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar}; | |
9fa01778 | 7 | use crate::mir::visit::MirVisitable; |
416331ca | 8 | use crate::ty::adjustment::PointerCast; |
3dfed10e | 9 | use crate::ty::codec::{TyDecoder, TyEncoder}; |
416331ca | 10 | use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; |
416331ca XL |
11 | use crate::ty::print::{FmtPrinter, Printer}; |
12 | use crate::ty::subst::{Subst, SubstsRef}; | |
13 | use crate::ty::{ | |
e74abb32 | 14 | self, AdtDef, CanonicalUserTypeAnnotations, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex, |
416331ca | 15 | }; |
dfeec247 XL |
16 | use rustc_hir as hir; |
17 | use rustc_hir::def::{CtorKind, Namespace}; | |
18 | use rustc_hir::def_id::DefId; | |
19 | use rustc_hir::{self, GeneratorKind}; | |
ba9703b0 | 20 | use rustc_target::abi::VariantIdx; |
e1599b0c | 21 | |
416331ca | 22 | use polonius_engine::Atom; |
3dfed10e | 23 | pub use rustc_ast::Mutability; |
a1dfa0c6 | 24 | use rustc_data_structures::fx::FxHashSet; |
f9f354fc | 25 | use rustc_data_structures::graph::dominators::{dominators, Dominators}; |
60c5eb7d | 26 | use rustc_data_structures::graph::{self, GraphSuccessors}; |
dfeec247 | 27 | use rustc_index::bit_set::BitMatrix; |
e74abb32 | 28 | use rustc_index::vec::{Idx, IndexVec}; |
dfeec247 XL |
29 | use rustc_serialize::{Decodable, Encodable}; |
30 | use rustc_span::symbol::Symbol; | |
31 | use rustc_span::{Span, DUMMY_SP}; | |
f035d41b | 32 | use rustc_target::abi; |
f9f354fc | 33 | use rustc_target::asm::InlineAsmRegOrRegClass; |
94b46f34 | 34 | use std::borrow::Cow; |
416331ca | 35 | use std::fmt::{self, Debug, Display, Formatter, Write}; |
f9f354fc | 36 | use std::ops::{Index, IndexMut}; |
94b46f34 | 37 | use std::slice; |
ba9703b0 | 38 | use std::{iter, mem, option}; |
83c7162d | 39 | |
f9f354fc | 40 | use self::predecessors::{PredecessorCache, Predecessors}; |
dfeec247 | 41 | pub use self::query::*; |
3157f602 | 42 | |
f035d41b | 43 | pub mod coverage; |
ff7c6d11 XL |
44 | pub mod interpret; |
45 | pub mod mono; | |
f9f354fc | 46 | mod predecessors; |
dfeec247 | 47 | mod query; |
94b46f34 | 48 | pub mod tcx; |
f035d41b XL |
49 | pub mod terminator; |
50 | pub use terminator::*; | |
94b46f34 | 51 | pub mod traversal; |
ba9703b0 | 52 | mod type_foldable; |
94b46f34 | 53 | pub mod visit; |
3157f602 | 54 | |
041b39d2 XL |
55 | /// Types for locals |
56 | type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>; | |
57 | ||
58 | pub trait HasLocalDecls<'tcx> { | |
59 | fn local_decls(&self) -> &LocalDecls<'tcx>; | |
60 | } | |
61 | ||
62 | impl<'tcx> HasLocalDecls<'tcx> for LocalDecls<'tcx> { | |
63 | fn local_decls(&self) -> &LocalDecls<'tcx> { | |
64 | self | |
65 | } | |
66 | } | |
67 | ||
dc9dc135 | 68 | impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { |
041b39d2 XL |
69 | fn local_decls(&self) -> &LocalDecls<'tcx> { |
70 | &self.local_decls | |
71 | } | |
72 | } | |
73 | ||
a1dfa0c6 XL |
74 | /// The various "big phases" that MIR goes through. |
75 | /// | |
3dfed10e XL |
76 | /// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the |
77 | /// dialects forbid certain variants or values in certain phases. | |
78 | /// | |
79 | /// Note: Each phase's validation checks all invariants of the *previous* phases' dialects. A phase | |
80 | /// that changes the dialect documents what invariants must be upheld *after* that phase finishes. | |
81 | /// | |
e1599b0c | 82 | /// Warning: ordering of variants is significant. |
3dfed10e | 83 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] |
ba9703b0 | 84 | #[derive(HashStable)] |
a1dfa0c6 XL |
85 | pub enum MirPhase { |
86 | Build = 0, | |
3dfed10e XL |
87 | // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query). |
88 | // We used to have this for pre-miri MIR based const eval. | |
a1dfa0c6 | 89 | Const = 1, |
3dfed10e XL |
90 | /// This phase checks the MIR for promotable elements and takes them out of the main MIR body |
91 | /// by creating a new MIR body per promoted element. After this phase (and thus the termination | |
92 | /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir` | |
93 | /// query. | |
94 | ConstPromotion = 2, | |
95 | /// After this phase | |
96 | /// * the only `AggregateKind`s allowed are `Array` and `Generator`, | |
97 | /// * `DropAndReplace` is gone for good | |
98 | /// * `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop` terminator | |
99 | /// means that the auto-generated drop glue will be invoked. | |
100 | DropLowering = 3, | |
101 | /// After this phase, generators are explicit state machines (no more `Yield`). | |
102 | /// `AggregateKind::Generator` is gone for good. | |
103 | GeneratorLowering = 4, | |
104 | Optimization = 5, | |
a1dfa0c6 XL |
105 | } |
106 | ||
107 | impl MirPhase { | |
e1599b0c | 108 | /// Gets the index of the current MirPhase within the set of all `MirPhase`s. |
a1dfa0c6 XL |
109 | pub fn phase_index(&self) -> usize { |
110 | *self as usize | |
111 | } | |
112 | } | |
113 | ||
e1599b0c | 114 | /// The lowered representation of a single function. |
3dfed10e | 115 | #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)] |
dc9dc135 | 116 | pub struct Body<'tcx> { |
e1599b0c | 117 | /// A list of basic blocks. References to basic block use a newtyped index type `BasicBlock` |
92a42be0 | 118 | /// that indexes into this vector. |
3157f602 | 119 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, |
e9174d1e | 120 | |
a1dfa0c6 XL |
121 | /// Records how far through the "desugaring and optimization" process this particular |
122 | /// MIR has traversed. This is particularly useful when inlining, since in that context | |
123 | /// we instantiate the promoted constants and add them to our promoted vector -- but those | |
124 | /// promoted items have already been optimized, whereas ours have not. This field allows | |
125 | /// us to see the difference and forego optimization on the inlined promoted items. | |
126 | pub phase: MirPhase, | |
127 | ||
e1599b0c | 128 | /// A list of source scopes; these are referenced by statements |
94b46f34 XL |
129 | /// and used for debuginfo. Indexed by a `SourceScope`. |
130 | pub source_scopes: IndexVec<SourceScope, SourceScopeData>, | |
54a0048b | 131 | |
e1599b0c | 132 | /// The yield type of the function, if it is a generator. |
ea8adc8c XL |
133 | pub yield_ty: Option<Ty<'tcx>>, |
134 | ||
e1599b0c | 135 | /// Generator drop glue. |
f9f354fc | 136 | pub generator_drop: Option<Box<Body<'tcx>>>, |
ea8adc8c XL |
137 | |
138 | /// The layout of a generator. Produced by the state transformation. | |
139 | pub generator_layout: Option<GeneratorLayout<'tcx>>, | |
140 | ||
60c5eb7d XL |
141 | /// If this is a generator then record the type of source expression that caused this generator |
142 | /// to be created. | |
143 | pub generator_kind: Option<GeneratorKind>, | |
144 | ||
c30ab7b3 SL |
145 | /// Declarations of locals. |
146 | /// | |
147 | /// The first local is the return value pointer, followed by `arg_count` | |
148 | /// locals for the function arguments, followed by any user-declared | |
149 | /// variables and temporaries. | |
041b39d2 | 150 | pub local_decls: LocalDecls<'tcx>, |
92a42be0 | 151 | |
e1599b0c | 152 | /// User type annotations. |
0731742a XL |
153 | pub user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, |
154 | ||
e1599b0c | 155 | /// The number of arguments this function takes. |
c30ab7b3 SL |
156 | /// |
157 | /// Starting at local 1, `arg_count` locals will be provided by the caller | |
158 | /// and can be assumed to be initialized. | |
159 | /// | |
160 | /// If this MIR was built for a constant, this will be 0. | |
161 | pub arg_count: usize, | |
7453a54e | 162 | |
c30ab7b3 SL |
163 | /// Mark an argument local (which must be a tuple) as getting passed as |
164 | /// its individual components at the LLVM level. | |
165 | /// | |
166 | /// This is used for the "rust-call" ABI. | |
167 | pub spread_arg: Option<Local>, | |
168 | ||
60c5eb7d XL |
169 | /// Debug information pertaining to user variables, including captures. |
170 | pub var_debug_info: Vec<VarDebugInfo<'tcx>>, | |
48663c56 | 171 | |
e1599b0c | 172 | /// A span representing this MIR, for error reporting. |
7453a54e | 173 | pub span: Span, |
dfeec247 | 174 | |
f9f354fc XL |
175 | /// Constants that are required to evaluate successfully for this MIR to be well-formed. |
176 | /// We hold in this field all the constants we are not able to evaluate yet. | |
177 | pub required_consts: Vec<Constant<'tcx>>, | |
178 | ||
179 | /// The user may be writing e.g. `&[(SOME_CELL, 42)][i].1` and this would get promoted, because | |
dfeec247 XL |
180 | /// we'd statically know that no thing with interior mutability will ever be available to the |
181 | /// user without some serious unsafe code. Now this means that our promoted is actually | |
f035d41b XL |
182 | /// `&[(SOME_CELL, 42)]` and the MIR using it will do the `&promoted[i].1` projection because |
183 | /// the index may be a runtime value. Such a promoted value is illegal because it has reachable | |
dfeec247 XL |
184 | /// interior mutability. This flag just makes this situation very obvious where the previous |
185 | /// implementation without the flag hid this situation silently. | |
186 | /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components. | |
187 | pub ignore_interior_mut_in_const_validation: bool, | |
f9f354fc XL |
188 | |
189 | predecessor_cache: PredecessorCache, | |
e9174d1e SL |
190 | } |
191 | ||
dc9dc135 | 192 | impl<'tcx> Body<'tcx> { |
94b46f34 XL |
193 | pub fn new( |
194 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, | |
195 | source_scopes: IndexVec<SourceScope, SourceScopeData>, | |
0731742a XL |
196 | local_decls: LocalDecls<'tcx>, |
197 | user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, | |
94b46f34 | 198 | arg_count: usize, |
60c5eb7d | 199 | var_debug_info: Vec<VarDebugInfo<'tcx>>, |
94b46f34 | 200 | span: Span, |
dfeec247 | 201 | generator_kind: Option<GeneratorKind>, |
94b46f34 | 202 | ) -> Self { |
e1599b0c | 203 | // We need `arg_count` locals, and one for the return place. |
94b46f34 | 204 | assert!( |
74b04a01 | 205 | local_decls.len() > arg_count, |
94b46f34 XL |
206 | "expected at least {} locals, got {}", |
207 | arg_count + 1, | |
208 | local_decls.len() | |
209 | ); | |
c30ab7b3 | 210 | |
dc9dc135 | 211 | Body { |
a1dfa0c6 | 212 | phase: MirPhase::Build, |
041b39d2 | 213 | basic_blocks, |
94b46f34 | 214 | source_scopes, |
60c5eb7d | 215 | yield_ty: None, |
ea8adc8c XL |
216 | generator_drop: None, |
217 | generator_layout: None, | |
60c5eb7d | 218 | generator_kind, |
041b39d2 | 219 | local_decls, |
0731742a | 220 | user_type_annotations, |
041b39d2 | 221 | arg_count, |
c30ab7b3 | 222 | spread_arg: None, |
60c5eb7d | 223 | var_debug_info, |
041b39d2 | 224 | span, |
f9f354fc | 225 | required_consts: Vec::new(), |
dfeec247 | 226 | ignore_interior_mut_in_const_validation: false, |
f9f354fc | 227 | predecessor_cache: PredecessorCache::new(), |
3157f602 XL |
228 | } |
229 | } | |
230 | ||
dfeec247 XL |
231 | /// Returns a partially initialized MIR body containing only a list of basic blocks. |
232 | /// | |
233 | /// The returned MIR contains no `LocalDecl`s (even for the return place) or source scopes. It | |
234 | /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different | |
235 | /// crate. | |
236 | pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self { | |
237 | Body { | |
238 | phase: MirPhase::Build, | |
239 | basic_blocks, | |
240 | source_scopes: IndexVec::new(), | |
241 | yield_ty: None, | |
242 | generator_drop: None, | |
243 | generator_layout: None, | |
244 | local_decls: IndexVec::new(), | |
245 | user_type_annotations: IndexVec::new(), | |
246 | arg_count: 0, | |
247 | spread_arg: None, | |
248 | span: DUMMY_SP, | |
f9f354fc | 249 | required_consts: Vec::new(), |
dfeec247 XL |
250 | generator_kind: None, |
251 | var_debug_info: Vec::new(), | |
252 | ignore_interior_mut_in_const_validation: false, | |
f9f354fc | 253 | predecessor_cache: PredecessorCache::new(), |
dfeec247 XL |
254 | } |
255 | } | |
256 | ||
3157f602 XL |
257 | #[inline] |
258 | pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> { | |
259 | &self.basic_blocks | |
260 | } | |
261 | ||
f9f354fc XL |
262 | #[inline] |
263 | pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { | |
264 | // Because the user could mutate basic block terminators via this reference, we need to | |
265 | // invalidate the predecessor cache. | |
266 | // | |
267 | // FIXME: Use a finer-grained API for this, so only transformations that alter terminators | |
268 | // invalidate the predecessor cache. | |
269 | self.predecessor_cache.invalidate(); | |
270 | &mut self.basic_blocks | |
271 | } | |
272 | ||
273 | #[inline] | |
274 | pub fn basic_blocks_and_local_decls_mut( | |
275 | &mut self, | |
276 | ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) { | |
277 | self.predecessor_cache.invalidate(); | |
278 | (&mut self.basic_blocks, &mut self.local_decls) | |
279 | } | |
280 | ||
f035d41b XL |
281 | #[inline] |
282 | pub fn basic_blocks_local_decls_mut_and_var_debug_info( | |
283 | &mut self, | |
284 | ) -> ( | |
285 | &mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, | |
286 | &mut LocalDecls<'tcx>, | |
287 | &mut Vec<VarDebugInfo<'tcx>>, | |
288 | ) { | |
289 | self.predecessor_cache.invalidate(); | |
290 | (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info) | |
291 | } | |
292 | ||
e74abb32 XL |
293 | /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the |
294 | /// `START_BLOCK`. | |
295 | pub fn is_cfg_cyclic(&self) -> bool { | |
296 | graph::is_cyclic(self) | |
297 | } | |
298 | ||
c30ab7b3 SL |
299 | #[inline] |
300 | pub fn local_kind(&self, local: Local) -> LocalKind { | |
b7449926 | 301 | let index = local.as_usize(); |
c30ab7b3 | 302 | if index == 0 { |
94b46f34 XL |
303 | debug_assert!( |
304 | self.local_decls[local].mutability == Mutability::Mut, | |
305 | "return place should be mutable" | |
306 | ); | |
c30ab7b3 SL |
307 | |
308 | LocalKind::ReturnPointer | |
309 | } else if index < self.arg_count + 1 { | |
310 | LocalKind::Arg | |
60c5eb7d | 311 | } else if self.local_decls[local].is_user_variable() { |
c30ab7b3 SL |
312 | LocalKind::Var |
313 | } else { | |
c30ab7b3 SL |
314 | LocalKind::Temp |
315 | } | |
316 | } | |
317 | ||
318 | /// Returns an iterator over all temporaries. | |
319 | #[inline] | |
94b46f34 XL |
320 | pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { |
321 | (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { | |
c30ab7b3 | 322 | let local = Local::new(index); |
dfeec247 | 323 | if self.local_decls[local].is_user_variable() { None } else { Some(local) } |
c30ab7b3 SL |
324 | }) |
325 | } | |
326 | ||
327 | /// Returns an iterator over all user-declared locals. | |
328 | #[inline] | |
94b46f34 XL |
329 | pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { |
330 | (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { | |
c30ab7b3 | 331 | let local = Local::new(index); |
60c5eb7d | 332 | self.local_decls[local].is_user_variable().then_some(local) |
c30ab7b3 | 333 | }) |
3157f602 XL |
334 | } |
335 | ||
a1dfa0c6 XL |
336 | /// Returns an iterator over all user-declared mutable locals. |
337 | #[inline] | |
338 | pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { | |
339 | (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { | |
340 | let local = Local::new(index); | |
341 | let decl = &self.local_decls[local]; | |
60c5eb7d | 342 | if decl.is_user_variable() && decl.mutability == Mutability::Mut { |
a1dfa0c6 XL |
343 | Some(local) |
344 | } else { | |
345 | None | |
346 | } | |
347 | }) | |
348 | } | |
349 | ||
83c7162d XL |
350 | /// Returns an iterator over all user-declared mutable arguments and locals. |
351 | #[inline] | |
94b46f34 | 352 | pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { |
83c7162d XL |
353 | (1..self.local_decls.len()).filter_map(move |index| { |
354 | let local = Local::new(index); | |
355 | let decl = &self.local_decls[local]; | |
60c5eb7d | 356 | if (decl.is_user_variable() || index < self.arg_count + 1) |
94b46f34 | 357 | && decl.mutability == Mutability::Mut |
83c7162d XL |
358 | { |
359 | Some(local) | |
360 | } else { | |
361 | None | |
362 | } | |
363 | }) | |
364 | } | |
365 | ||
c30ab7b3 SL |
366 | /// Returns an iterator over all function arguments. |
367 | #[inline] | |
60c5eb7d | 368 | pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator { |
c30ab7b3 | 369 | let arg_count = self.arg_count; |
60c5eb7d | 370 | (1..arg_count + 1).map(Local::new) |
e9174d1e | 371 | } |
9e0c209e | 372 | |
c30ab7b3 | 373 | /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all |
ff7c6d11 | 374 | /// locals that are neither arguments nor the return place). |
c30ab7b3 | 375 | #[inline] |
60c5eb7d | 376 | pub fn vars_and_temps_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator { |
c30ab7b3 SL |
377 | let arg_count = self.arg_count; |
378 | let local_count = self.local_decls.len(); | |
94b46f34 | 379 | (arg_count + 1..local_count).map(Local::new) |
9e0c209e SL |
380 | } |
381 | ||
382 | /// Changes a statement to a nop. This is both faster than deleting instructions and avoids | |
383 | /// invalidating statement indices in `Location`s. | |
384 | pub fn make_statement_nop(&mut self, location: Location) { | |
60c5eb7d | 385 | let block = &mut self.basic_blocks[location.block]; |
9e0c209e SL |
386 | debug_assert!(location.statement_index < block.statements.len()); |
387 | block.statements[location.statement_index].make_nop() | |
388 | } | |
ea8adc8c XL |
389 | |
390 | /// Returns the source info associated with `location`. | |
391 | pub fn source_info(&self, location: Location) -> &SourceInfo { | |
392 | let block = &self[location.block]; | |
393 | let stmts = &block.statements; | |
394 | let idx = location.statement_index; | |
abe05a73 | 395 | if idx < stmts.len() { |
ea8adc8c XL |
396 | &stmts[idx].source_info |
397 | } else { | |
0bf4aa26 | 398 | assert_eq!(idx, stmts.len()); |
ea8adc8c XL |
399 | &block.terminator().source_info |
400 | } | |
401 | } | |
abe05a73 | 402 | |
9fa01778 | 403 | /// Checks if `sub` is a sub scope of `sup` |
94b46f34 | 404 | pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool { |
0bf4aa26 | 405 | while sub != sup { |
94b46f34 XL |
406 | match self.source_scopes[sub].parent_scope { |
407 | None => return false, | |
408 | Some(p) => sub = p, | |
409 | } | |
410 | } | |
0bf4aa26 | 411 | true |
94b46f34 XL |
412 | } |
413 | ||
e1599b0c | 414 | /// Returns the return type; it always return first element from `local_decls` array. |
f9f354fc | 415 | #[inline] |
abe05a73 | 416 | pub fn return_ty(&self) -> Ty<'tcx> { |
ff7c6d11 | 417 | self.local_decls[RETURN_PLACE].ty |
abe05a73 | 418 | } |
b7449926 | 419 | |
e1599b0c | 420 | /// Gets the location of the terminator for the given block. |
f9f354fc | 421 | #[inline] |
b7449926 | 422 | pub fn terminator_loc(&self, bb: BasicBlock) -> Location { |
416331ca | 423 | Location { block: bb, statement_index: self[bb].statements.len() } |
b7449926 | 424 | } |
f9f354fc XL |
425 | |
426 | #[inline] | |
427 | pub fn predecessors(&self) -> impl std::ops::Deref<Target = Predecessors> + '_ { | |
428 | self.predecessor_cache.compute(&self.basic_blocks) | |
429 | } | |
430 | ||
431 | #[inline] | |
432 | pub fn dominators(&self) -> Dominators<BasicBlock> { | |
433 | dominators(self) | |
434 | } | |
ea8adc8c XL |
435 | } |
436 | ||
3dfed10e | 437 | #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)] |
ea8adc8c XL |
438 | pub enum Safety { |
439 | Safe, | |
440 | /// Unsafe because of a PushUnsafeBlock | |
441 | BuiltinUnsafe, | |
442 | /// Unsafe because of an unsafe fn | |
443 | FnUnsafe, | |
444 | /// Unsafe because of an `unsafe` block | |
532ac7d7 | 445 | ExplicitUnsafe(hir::HirId), |
e9174d1e SL |
446 | } |
447 | ||
dc9dc135 | 448 | impl<'tcx> Index<BasicBlock> for Body<'tcx> { |
9cc50fc6 SL |
449 | type Output = BasicBlockData<'tcx>; |
450 | ||
451 | #[inline] | |
452 | fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { | |
3157f602 | 453 | &self.basic_blocks()[index] |
9cc50fc6 SL |
454 | } |
455 | } | |
456 | ||
f9f354fc XL |
457 | impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> { |
458 | #[inline] | |
459 | fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { | |
460 | &mut self.basic_blocks_mut()[index] | |
461 | } | |
462 | } | |
463 | ||
60c5eb7d | 464 | #[derive(Copy, Clone, Debug, HashStable, TypeFoldable)] |
ff7c6d11 | 465 | pub enum ClearCrossCrate<T> { |
ea8adc8c | 466 | Clear, |
94b46f34 | 467 | Set(T), |
ea8adc8c XL |
468 | } |
469 | ||
8faf50e0 | 470 | impl<T> ClearCrossCrate<T> { |
ba9703b0 | 471 | pub fn as_ref(&self) -> ClearCrossCrate<&T> { |
60c5eb7d XL |
472 | match self { |
473 | ClearCrossCrate::Clear => ClearCrossCrate::Clear, | |
474 | ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v), | |
475 | } | |
476 | } | |
477 | ||
8faf50e0 XL |
478 | pub fn assert_crate_local(self) -> T { |
479 | match self { | |
480 | ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), | |
481 | ClearCrossCrate::Set(v) => v, | |
482 | } | |
483 | } | |
484 | } | |
485 | ||
f035d41b XL |
486 | const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; |
487 | const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; | |
488 | ||
3dfed10e | 489 | impl<'tcx, E: TyEncoder<'tcx>, T: Encodable<E>> Encodable<E> for ClearCrossCrate<T> { |
f035d41b | 490 | #[inline] |
3dfed10e XL |
491 | fn encode(&self, e: &mut E) -> Result<(), E::Error> { |
492 | if E::CLEAR_CROSS_CRATE { | |
493 | return Ok(()); | |
494 | } | |
495 | ||
f035d41b XL |
496 | match *self { |
497 | ClearCrossCrate::Clear => TAG_CLEAR_CROSS_CRATE_CLEAR.encode(e), | |
498 | ClearCrossCrate::Set(ref val) => { | |
499 | TAG_CLEAR_CROSS_CRATE_SET.encode(e)?; | |
500 | val.encode(e) | |
501 | } | |
502 | } | |
503 | } | |
504 | } | |
3dfed10e | 505 | impl<'tcx, D: TyDecoder<'tcx>, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> { |
f035d41b | 506 | #[inline] |
3dfed10e XL |
507 | fn decode(d: &mut D) -> Result<ClearCrossCrate<T>, D::Error> { |
508 | if D::CLEAR_CROSS_CRATE { | |
509 | return Ok(ClearCrossCrate::Clear); | |
510 | } | |
511 | ||
f035d41b XL |
512 | let discr = u8::decode(d)?; |
513 | ||
514 | match discr { | |
515 | TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(ClearCrossCrate::Clear), | |
516 | TAG_CLEAR_CROSS_CRATE_SET => { | |
517 | let val = T::decode(d)?; | |
518 | Ok(ClearCrossCrate::Set(val)) | |
519 | } | |
3dfed10e | 520 | tag => Err(d.error(&format!("Invalid tag for ClearCrossCrate: {:?}", tag))), |
f035d41b XL |
521 | } |
522 | } | |
523 | } | |
ea8adc8c | 524 | |
3157f602 XL |
525 | /// Grouped information about the source code origin of a MIR entity. |
526 | /// Intended to be inspected by diagnostics and debuginfo. | |
527 | /// Most passes can work with it as a whole, within a single function. | |
60c5eb7d | 528 | // The unofficial Cranelift backend, at least as of #65828, needs `SourceInfo` to implement `Eq` and |
e74abb32 | 529 | // `Hash`. Please ping @bjorn3 if removing them. |
3dfed10e | 530 | #[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] |
3157f602 | 531 | pub struct SourceInfo { |
e1599b0c | 532 | /// The source span for the AST pertaining to this MIR entity. |
3157f602 XL |
533 | pub span: Span, |
534 | ||
94b46f34 XL |
535 | /// The source scope, keeping track of which bindings can be |
536 | /// seen by debuginfo, active lint levels, `unsafe {...}`, etc. | |
537 | pub scope: SourceScope, | |
3157f602 XL |
538 | } |
539 | ||
f9f354fc XL |
540 | impl SourceInfo { |
541 | #[inline] | |
542 | pub fn outermost(span: Span) -> Self { | |
543 | SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE } | |
544 | } | |
545 | } | |
546 | ||
e9174d1e | 547 | /////////////////////////////////////////////////////////////////////////// |
dfeec247 | 548 | // Borrow kinds |
94b46f34 | 549 | |
3dfed10e | 550 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] |
ba9703b0 | 551 | #[derive(HashStable)] |
e9174d1e SL |
552 | pub enum BorrowKind { |
553 | /// Data must be immutable and is aliasable. | |
554 | Shared, | |
555 | ||
0bf4aa26 XL |
556 | /// The immediately borrowed place must be immutable, but projections from |
557 | /// it don't need to be. For example, a shallow borrow of `a.b` doesn't | |
558 | /// conflict with a mutable borrow of `a.b.c`. | |
559 | /// | |
560 | /// This is used when lowering matches: when matching on a place we want to | |
561 | /// ensure that place have the same value from the start of the match until | |
562 | /// an arm is selected. This prevents this code from compiling: | |
563 | /// | |
564 | /// let mut x = &Some(0); | |
565 | /// match *x { | |
566 | /// None => (), | |
567 | /// Some(_) if { x = &None; false } => (), | |
568 | /// Some(_) => (), | |
569 | /// } | |
570 | /// | |
571 | /// This can't be a shared borrow because mutably borrowing (*x as Some).0 | |
572 | /// should not prevent `if let None = x { ... }`, for example, because the | |
573 | /// mutating `(*x as Some).0` can't affect the discriminant of `x`. | |
574 | /// We can also report errors with this kind of borrow differently. | |
575 | Shallow, | |
576 | ||
9fa01778 | 577 | /// Data must be immutable but not aliasable. This kind of borrow |
e9174d1e | 578 | /// cannot currently be expressed by the user and is used only in |
b7449926 XL |
579 | /// implicit closure bindings. It is needed when the closure is |
580 | /// borrowing or mutating a mutable referent, e.g.: | |
e9174d1e | 581 | /// |
a1dfa0c6 XL |
582 | /// let x: &mut isize = ...; |
583 | /// let y = || *x += 5; | |
e9174d1e SL |
584 | /// |
585 | /// If we were to try to translate this closure into a more explicit | |
586 | /// form, we'd encounter an error with the code as written: | |
587 | /// | |
a1dfa0c6 XL |
588 | /// struct Env { x: & &mut isize } |
589 | /// let x: &mut isize = ...; | |
590 | /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn | |
591 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
e9174d1e | 592 | /// |
b7449926 | 593 | /// This is then illegal because you cannot mutate an `&mut` found |
e9174d1e SL |
594 | /// in an aliasable location. To solve, you'd have to translate with |
595 | /// an `&mut` borrow: | |
596 | /// | |
a1dfa0c6 XL |
597 | /// struct Env { x: & &mut isize } |
598 | /// let x: &mut isize = ...; | |
599 | /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x | |
600 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
e9174d1e SL |
601 | /// |
602 | /// Now the assignment to `**env.x` is legal, but creating a | |
603 | /// mutable pointer to `x` is not because `x` is not mutable. We | |
604 | /// could fix this by declaring `x` as `let mut x`. This is ok in | |
605 | /// user code, if awkward, but extra weird for closures, since the | |
606 | /// borrow is hidden. | |
607 | /// | |
608 | /// So we introduce a "unique imm" borrow -- the referent is | |
609 | /// immutable, but not aliasable. This solves the problem. For | |
610 | /// simplicity, we don't give users the way to express this | |
611 | /// borrow, it's just used when translating closures. | |
612 | Unique, | |
613 | ||
614 | /// Data is mutable and not aliasable. | |
2c00a5a8 | 615 | Mut { |
9fa01778 XL |
616 | /// `true` if this borrow arose from method-call auto-ref |
617 | /// (i.e., `adjustment::Adjust::Borrow`). | |
94b46f34 XL |
618 | allow_two_phase_borrow: bool, |
619 | }, | |
2c00a5a8 XL |
620 | } |
621 | ||
622 | impl BorrowKind { | |
623 | pub fn allows_two_phase_borrow(&self) -> bool { | |
624 | match *self { | |
0bf4aa26 XL |
625 | BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, |
626 | BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, | |
2c00a5a8 XL |
627 | } |
628 | } | |
e9174d1e SL |
629 | } |
630 | ||
631 | /////////////////////////////////////////////////////////////////////////// | |
632 | // Variables and temps | |
633 | ||
e74abb32 | 634 | rustc_index::newtype_index! { |
b7449926 | 635 | pub struct Local { |
532ac7d7 | 636 | derive [HashStable] |
abe05a73 | 637 | DEBUG_FORMAT = "_{}", |
ff7c6d11 | 638 | const RETURN_PLACE = 0, |
b7449926 XL |
639 | } |
640 | } | |
54a0048b | 641 | |
416331ca XL |
642 | impl Atom for Local { |
643 | fn index(self) -> usize { | |
644 | Idx::index(self) | |
645 | } | |
646 | } | |
647 | ||
dc9dc135 | 648 | /// Classifies locals into categories. See `Body::local_kind`. |
532ac7d7 | 649 | #[derive(PartialEq, Eq, Debug, HashStable)] |
c30ab7b3 | 650 | pub enum LocalKind { |
e1599b0c | 651 | /// User-declared variable binding. |
c30ab7b3 | 652 | Var, |
e1599b0c | 653 | /// Compiler-introduced temporary. |
c30ab7b3 | 654 | Temp, |
e1599b0c | 655 | /// Function argument. |
c30ab7b3 | 656 | Arg, |
e1599b0c | 657 | /// Location of function's return value. |
c30ab7b3 | 658 | ReturnPointer, |
e9174d1e SL |
659 | } |
660 | ||
3dfed10e | 661 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] |
8faf50e0 | 662 | pub struct VarBindingForm<'tcx> { |
94b46f34 XL |
663 | /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? |
664 | pub binding_mode: ty::BindingMode, | |
665 | /// If an explicit type was provided for this variable binding, | |
666 | /// this holds the source Span of that type. | |
667 | /// | |
9fa01778 | 668 | /// NOTE: if you want to change this to a `HirId`, be wary that |
94b46f34 XL |
669 | /// doing so breaks incremental compilation (as of this writing), |
670 | /// while a `Span` does not cause our tests to fail. | |
671 | pub opt_ty_info: Option<Span>, | |
8faf50e0 XL |
672 | /// Place of the RHS of the =, or the subject of the `match` where this |
673 | /// variable is initialized. None in the case of `let PATTERN;`. | |
674 | /// Some((None, ..)) in the case of and `let [mut] x = ...` because | |
675 | /// (a) the right-hand side isn't evaluated as a place expression. | |
676 | /// (b) it gives a way to separate this case from the remaining cases | |
677 | /// for diagnostics. | |
678 | pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>, | |
e1599b0c | 679 | /// The span of the pattern in which this variable was bound. |
b7449926 | 680 | pub pat_span: Span, |
94b46f34 XL |
681 | } |
682 | ||
3dfed10e | 683 | #[derive(Clone, Debug, TyEncodable, TyDecodable)] |
8faf50e0 | 684 | pub enum BindingForm<'tcx> { |
94b46f34 | 685 | /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. |
8faf50e0 | 686 | Var(VarBindingForm<'tcx>), |
94b46f34 | 687 | /// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit. |
0bf4aa26 | 688 | ImplicitSelf(ImplicitSelfKind), |
8faf50e0 XL |
689 | /// Reference used in a guard expression to ensure immutability. |
690 | RefForGuard, | |
94b46f34 XL |
691 | } |
692 | ||
0bf4aa26 | 693 | /// Represents what type of implicit self a function has, if any. |
3dfed10e | 694 | #[derive(Clone, Copy, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] |
0bf4aa26 XL |
695 | pub enum ImplicitSelfKind { |
696 | /// Represents a `fn x(self);`. | |
697 | Imm, | |
698 | /// Represents a `fn x(mut self);`. | |
699 | Mut, | |
700 | /// Represents a `fn x(&self);`. | |
701 | ImmRef, | |
702 | /// Represents a `fn x(&mut self);`. | |
703 | MutRef, | |
704 | /// Represents when a function does not have a self argument or | |
705 | /// when a function has a `self: X` argument. | |
416331ca | 706 | None, |
0bf4aa26 XL |
707 | } |
708 | ||
8faf50e0 | 709 | CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } |
94b46f34 | 710 | |
8faf50e0 | 711 | mod binding_form_impl { |
9fa01778 | 712 | use crate::ich::StableHashingContext; |
e74abb32 | 713 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
8faf50e0 XL |
714 | |
715 | impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> { | |
e74abb32 | 716 | fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { |
8faf50e0 XL |
717 | use super::BindingForm::*; |
718 | ::std::mem::discriminant(self).hash_stable(hcx, hasher); | |
719 | ||
720 | match self { | |
721 | Var(binding) => binding.hash_stable(hcx, hasher), | |
0bf4aa26 | 722 | ImplicitSelf(kind) => kind.hash_stable(hcx, hasher), |
8faf50e0 XL |
723 | RefForGuard => (), |
724 | } | |
725 | } | |
726 | } | |
727 | } | |
94b46f34 | 728 | |
0bf4aa26 XL |
729 | /// `BlockTailInfo` is attached to the `LocalDecl` for temporaries |
730 | /// created during evaluation of expressions in a block tail | |
731 | /// expression; that is, a block like `{ STMT_1; STMT_2; EXPR }`. | |
732 | /// | |
733 | /// It is used to improve diagnostics when such temporaries are | |
0731742a | 734 | /// involved in borrow_check errors, e.g., explanations of where the |
0bf4aa26 XL |
735 | /// temporaries come from, when their destructors are run, and/or how |
736 | /// one might revise the code to satisfy the borrow checker's rules. | |
3dfed10e | 737 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] |
0bf4aa26 XL |
738 | pub struct BlockTailInfo { |
739 | /// If `true`, then the value resulting from evaluating this tail | |
740 | /// expression is ignored by the block's expression context. | |
741 | /// | |
742 | /// Examples include `{ ...; tail };` and `let _ = { ...; tail };` | |
0731742a | 743 | /// but not e.g., `let _x = { ...; tail };` |
0bf4aa26 | 744 | pub tail_result_is_ignored: bool, |
f9f354fc XL |
745 | |
746 | /// `Span` of the tail expression. | |
747 | pub span: Span, | |
0bf4aa26 XL |
748 | } |
749 | ||
c30ab7b3 | 750 | /// A MIR local. |
7453a54e | 751 | /// |
c30ab7b3 | 752 | /// This can be a binding declared by the user, a temporary inserted by the compiler, a function |
ff7c6d11 | 753 | /// argument, or the return place. |
3dfed10e | 754 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
c30ab7b3 | 755 | pub struct LocalDecl<'tcx> { |
e1599b0c | 756 | /// Whether this is a mutable minding (i.e., `let x` or `let mut x`). |
c30ab7b3 | 757 | /// |
ff7c6d11 | 758 | /// Temporaries and the return place are always mutable. |
c30ab7b3 SL |
759 | pub mutability: Mutability, |
760 | ||
60c5eb7d | 761 | // FIXME(matthewjasper) Don't store in this in `Body` |
f9f354fc | 762 | pub local_info: Option<Box<LocalInfo<'tcx>>>, |
cc61c64b | 763 | |
9fa01778 | 764 | /// `true` if this is an internal local. |
ea8adc8c XL |
765 | /// |
766 | /// These locals are not based on types in the source code and are only used | |
767 | /// for a few desugarings at the moment. | |
768 | /// | |
769 | /// The generator transformation will sanity check the locals which are live | |
770 | /// across a suspension point against the type components of the generator | |
771 | /// which type checking knows are live across a suspension point. We need to | |
772 | /// flag drop flags to avoid triggering this check as they are introduced | |
773 | /// after typeck. | |
774 | /// | |
775 | /// Unsafety checking will also ignore dereferences of these locals, | |
776 | /// so they can be used for raw pointers only used in a desugaring. | |
777 | /// | |
778 | /// This should be sound because the drop flags are fully algebraic, and | |
779 | /// therefore don't affect the OIBIT or outlives properties of the | |
780 | /// generator. | |
781 | pub internal: bool, | |
782 | ||
0bf4aa26 XL |
783 | /// If this local is a temporary and `is_block_tail` is `Some`, |
784 | /// then it is a temporary created for evaluation of some | |
785 | /// subexpression of some block's tail expression (with no | |
786 | /// intervening statement context). | |
60c5eb7d | 787 | // FIXME(matthewjasper) Don't store in this in `Body` |
0bf4aa26 XL |
788 | pub is_block_tail: Option<BlockTailInfo>, |
789 | ||
e1599b0c | 790 | /// The type of this local. |
b039eaaf | 791 | pub ty: Ty<'tcx>, |
54a0048b | 792 | |
b7449926 | 793 | /// If the user manually ascribed a type to this variable, |
0731742a | 794 | /// e.g., via `let x: T`, then we carry that type here. The MIR |
b7449926 XL |
795 | /// borrow checker needs this information since it can affect |
796 | /// region inference. | |
60c5eb7d | 797 | // FIXME(matthewjasper) Don't store in this in `Body` |
f9f354fc | 798 | pub user_ty: Option<Box<UserTypeProjections>>, |
b7449926 | 799 | |
0731742a | 800 | /// The *syntactic* (i.e., not visibility) source scope the local is defined |
ea8adc8c XL |
801 | /// in. If the local was defined in a let-statement, this |
802 | /// is *within* the let-statement, rather than outside | |
803 | /// of it. | |
ff7c6d11 | 804 | /// |
94b46f34 XL |
805 | /// This is needed because the visibility source scope of locals within |
806 | /// a let-statement is weird. | |
ff7c6d11 XL |
807 | /// |
808 | /// The reason is that we want the local to be *within* the let-statement | |
809 | /// for lint purposes, but we want the local to be *after* the let-statement | |
810 | /// for names-in-scope purposes. | |
811 | /// | |
812 | /// That's it, if we have a let-statement like the one in this | |
813 | /// function: | |
814 | /// | |
815 | /// ``` | |
816 | /// fn foo(x: &str) { | |
817 | /// #[allow(unused_mut)] | |
818 | /// let mut x: u32 = { // <- one unused mut | |
819 | /// let mut y: u32 = x.parse().unwrap(); | |
820 | /// y + 2 | |
821 | /// }; | |
822 | /// drop(x); | |
823 | /// } | |
824 | /// ``` | |
825 | /// | |
826 | /// Then, from a lint point of view, the declaration of `x: u32` | |
827 | /// (and `y: u32`) are within the `#[allow(unused_mut)]` scope - the | |
828 | /// lint scopes are the same as the AST/HIR nesting. | |
829 | /// | |
830 | /// However, from a name lookup point of view, the scopes look more like | |
831 | /// as if the let-statements were `match` expressions: | |
832 | /// | |
833 | /// ``` | |
834 | /// fn foo(x: &str) { | |
835 | /// match { | |
836 | /// match x.parse().unwrap() { | |
837 | /// y => y + 2 | |
838 | /// } | |
839 | /// } { | |
840 | /// x => drop(x) | |
841 | /// }; | |
842 | /// } | |
843 | /// ``` | |
844 | /// | |
845 | /// We care about the name-lookup scopes for debuginfo - if the | |
846 | /// debuginfo instruction pointer is at the call to `x.parse()`, we | |
847 | /// want `x` to refer to `x: &str`, but if it is at the call to | |
848 | /// `drop(x)`, we want it to refer to `x: u32`. | |
849 | /// | |
850 | /// To allow both uses to work, we need to have more than a single scope | |
60c5eb7d XL |
851 | /// for a local. We have the `source_info.scope` represent the "syntactic" |
852 | /// lint scope (with a variable being under its let block) while the | |
853 | /// `var_debug_info.source_info.scope` represents the "local variable" | |
ff7c6d11 XL |
854 | /// scope (where the "rest" of a block is under all prior let-statements). |
855 | /// | |
856 | /// The end result looks like this: | |
857 | /// | |
858 | /// ```text | |
859 | /// ROOT SCOPE | |
860 | /// │{ argument x: &str } | |
861 | /// │ | |
e1599b0c XL |
862 | /// │ │{ #[allow(unused_mut)] } // This is actually split into 2 scopes |
863 | /// │ │ // in practice because I'm lazy. | |
ff7c6d11 | 864 | /// │ │ |
94b46f34 | 865 | /// │ │← x.source_info.scope |
ff7c6d11 XL |
866 | /// │ │← `x.parse().unwrap()` |
867 | /// │ │ | |
94b46f34 | 868 | /// │ │ │← y.source_info.scope |
ff7c6d11 XL |
869 | /// │ │ |
870 | /// │ │ │{ let y: u32 } | |
871 | /// │ │ │ | |
60c5eb7d | 872 | /// │ │ │← y.var_debug_info.source_info.scope |
ff7c6d11 XL |
873 | /// │ │ │← `y + 2` |
874 | /// │ | |
875 | /// │ │{ let x: u32 } | |
60c5eb7d | 876 | /// │ │← x.var_debug_info.source_info.scope |
e1599b0c | 877 | /// │ │← `drop(x)` // This accesses `x: u32`. |
ff7c6d11 | 878 | /// ``` |
94b46f34 | 879 | pub source_info: SourceInfo, |
60c5eb7d | 880 | } |
94b46f34 | 881 | |
f9f354fc XL |
882 | // `LocalDecl` is used a lot. Make sure it doesn't unintentionally get bigger. |
883 | #[cfg(target_arch = "x86_64")] | |
884 | static_assert_size!(LocalDecl<'_>, 56); | |
885 | ||
3dfed10e XL |
886 | /// Extra information about a some locals that's used for diagnostics and for |
887 | /// classifying variables into local variables, statics, etc, which is needed e.g. | |
888 | /// for unsafety checking. | |
889 | /// | |
890 | /// Not used for non-StaticRef temporaries, the return place, or anonymous | |
891 | /// function parameters. | |
892 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] | |
60c5eb7d XL |
893 | pub enum LocalInfo<'tcx> { |
894 | /// A user-defined local variable or function parameter | |
895 | /// | |
896 | /// The `BindingForm` is solely used for local diagnostics when generating | |
897 | /// warnings/errors when compiling the current crate, and therefore it need | |
898 | /// not be visible across crates. | |
899 | User(ClearCrossCrate<BindingForm<'tcx>>), | |
900 | /// A temporary created that references the static with the given `DefId`. | |
901 | StaticRef { def_id: DefId, is_thread_local: bool }, | |
c30ab7b3 SL |
902 | } |
903 | ||
904 | impl<'tcx> LocalDecl<'tcx> { | |
9fa01778 | 905 | /// Returns `true` only if local is a binding that can itself be |
94b46f34 XL |
906 | /// made mutable via the addition of the `mut` keyword, namely |
907 | /// something like the occurrences of `x` in: | |
908 | /// - `fn foo(x: Type) { ... }`, | |
909 | /// - `let x = ...`, | |
910 | /// - or `match ... { C(x) => ... }` | |
911 | pub fn can_be_made_mutable(&self) -> bool { | |
60c5eb7d | 912 | match self.local_info { |
f9f354fc | 913 | Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { |
94b46f34 XL |
914 | binding_mode: ty::BindingMode::BindByValue(_), |
915 | opt_ty_info: _, | |
8faf50e0 | 916 | opt_match_place: _, |
b7449926 | 917 | pat_span: _, |
f9f354fc | 918 | })))) => true, |
94b46f34 | 919 | |
f9f354fc | 920 | Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( |
dfeec247 | 921 | ImplicitSelfKind::Imm, |
f9f354fc | 922 | )))) => true, |
0bf4aa26 | 923 | |
94b46f34 XL |
924 | _ => false, |
925 | } | |
926 | } | |
927 | ||
9fa01778 | 928 | /// Returns `true` if local is definitely not a `ref ident` or |
94b46f34 XL |
929 | /// `ref mut ident` binding. (Such bindings cannot be made into |
930 | /// mutable bindings, but the inverse does not necessarily hold). | |
931 | pub fn is_nonref_binding(&self) -> bool { | |
60c5eb7d | 932 | match self.local_info { |
f9f354fc | 933 | Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { |
94b46f34 XL |
934 | binding_mode: ty::BindingMode::BindByValue(_), |
935 | opt_ty_info: _, | |
8faf50e0 | 936 | opt_match_place: _, |
b7449926 | 937 | pat_span: _, |
f9f354fc | 938 | })))) => true, |
94b46f34 | 939 | |
f9f354fc | 940 | Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_)))) => true, |
60c5eb7d XL |
941 | |
942 | _ => false, | |
943 | } | |
944 | } | |
94b46f34 | 945 | |
60c5eb7d XL |
946 | /// Returns `true` if this variable is a named variable or function |
947 | /// parameter declared by the user. | |
948 | #[inline] | |
949 | pub fn is_user_variable(&self) -> bool { | |
950 | match self.local_info { | |
f9f354fc | 951 | Some(box LocalInfo::User(_)) => true, |
94b46f34 XL |
952 | _ => false, |
953 | } | |
954 | } | |
955 | ||
dc9dc135 XL |
956 | /// Returns `true` if this is a reference to a variable bound in a `match` |
957 | /// expression that is used to access said variable for the guard of the | |
958 | /// match arm. | |
959 | pub fn is_ref_for_guard(&self) -> bool { | |
60c5eb7d | 960 | match self.local_info { |
f9f354fc | 961 | Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) => true, |
60c5eb7d XL |
962 | _ => false, |
963 | } | |
964 | } | |
965 | ||
966 | /// Returns `Some` if this is a reference to a static item that is used to | |
967 | /// access that static | |
968 | pub fn is_ref_to_static(&self) -> bool { | |
969 | match self.local_info { | |
f9f354fc | 970 | Some(box LocalInfo::StaticRef { .. }) => true, |
60c5eb7d XL |
971 | _ => false, |
972 | } | |
973 | } | |
974 | ||
975 | /// Returns `Some` if this is a reference to a static item that is used to | |
976 | /// access that static | |
977 | pub fn is_ref_to_thread_local(&self) -> bool { | |
978 | match self.local_info { | |
f9f354fc | 979 | Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local, |
dc9dc135 XL |
980 | _ => false, |
981 | } | |
982 | } | |
983 | ||
984 | /// Returns `true` is the local is from a compiler desugaring, e.g., | |
985 | /// `__next` from a `for` loop. | |
986 | #[inline] | |
987 | pub fn from_compiler_desugaring(&self) -> bool { | |
416331ca | 988 | self.source_info.span.desugaring_kind().is_some() |
dc9dc135 XL |
989 | } |
990 | ||
f9f354fc | 991 | /// Creates a new `LocalDecl` for a temporary: mutable, non-internal. |
c30ab7b3 | 992 | #[inline] |
f9f354fc XL |
993 | pub fn new(ty: Ty<'tcx>, span: Span) -> Self { |
994 | Self::with_source_info(ty, SourceInfo::outermost(span)) | |
995 | } | |
996 | ||
997 | /// Like `LocalDecl::new`, but takes a `SourceInfo` instead of a `Span`. | |
998 | #[inline] | |
999 | pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self { | |
1000 | LocalDecl { | |
1001 | mutability: Mutability::Mut, | |
1002 | local_info: None, | |
1003 | internal: false, | |
1004 | is_block_tail: None, | |
1005 | ty, | |
1006 | user_ty: None, | |
1007 | source_info, | |
1008 | } | |
1009 | } | |
1010 | ||
1011 | /// Converts `self` into same `LocalDecl` except tagged as internal. | |
1012 | #[inline] | |
1013 | pub fn internal(mut self) -> Self { | |
1014 | self.internal = true; | |
1015 | self | |
b7449926 XL |
1016 | } |
1017 | ||
0bf4aa26 | 1018 | /// Converts `self` into same `LocalDecl` except tagged as immutable. |
b7449926 | 1019 | #[inline] |
0bf4aa26 XL |
1020 | pub fn immutable(mut self) -> Self { |
1021 | self.mutability = Mutability::Not; | |
1022 | self | |
1023 | } | |
1024 | ||
1025 | /// Converts `self` into same `LocalDecl` except tagged as internal temporary. | |
1026 | #[inline] | |
1027 | pub fn block_tail(mut self, info: BlockTailInfo) -> Self { | |
1028 | assert!(self.is_block_tail.is_none()); | |
1029 | self.is_block_tail = Some(info); | |
1030 | self | |
ea8adc8c | 1031 | } |
a7813a04 XL |
1032 | } |
1033 | ||
60c5eb7d | 1034 | /// Debug information pertaining to a user variable. |
3dfed10e | 1035 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
60c5eb7d | 1036 | pub struct VarDebugInfo<'tcx> { |
f9f354fc | 1037 | pub name: Symbol, |
60c5eb7d XL |
1038 | |
1039 | /// Source info of the user variable, including the scope | |
1040 | /// within which the variable is visible (to debuginfo) | |
1041 | /// (see `LocalDecl`'s `source_info` field for more details). | |
1042 | pub source_info: SourceInfo, | |
a7813a04 | 1043 | |
60c5eb7d XL |
1044 | /// Where the data for this user variable is to be found. |
1045 | /// NOTE(eddyb) There's an unenforced invariant that this `Place` is | |
1046 | /// based on a `Local`, not a `Static`, and contains no indexing. | |
1047 | pub place: Place<'tcx>, | |
e9174d1e SL |
1048 | } |
1049 | ||
e9174d1e SL |
1050 | /////////////////////////////////////////////////////////////////////////// |
1051 | // BasicBlock | |
1052 | ||
e74abb32 | 1053 | rustc_index::newtype_index! { |
b7449926 | 1054 | pub struct BasicBlock { |
532ac7d7 | 1055 | derive [HashStable] |
b7449926 XL |
1056 | DEBUG_FORMAT = "bb{}", |
1057 | const START_BLOCK = 0, | |
1058 | } | |
1059 | } | |
abe05a73 XL |
1060 | |
1061 | impl BasicBlock { | |
1062 | pub fn start_location(self) -> Location { | |
416331ca | 1063 | Location { block: self, statement_index: 0 } |
abe05a73 XL |
1064 | } |
1065 | } | |
e9174d1e SL |
1066 | |
1067 | /////////////////////////////////////////////////////////////////////////// | |
54a0048b | 1068 | // BasicBlockData and Terminator |
e9174d1e | 1069 | |
3dfed10e | 1070 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
b039eaaf | 1071 | pub struct BasicBlockData<'tcx> { |
54a0048b | 1072 | /// List of statements in this block. |
b039eaaf | 1073 | pub statements: Vec<Statement<'tcx>>, |
54a0048b SL |
1074 | |
1075 | /// Terminator for this block. | |
1076 | /// | |
9fa01778 | 1077 | /// N.B., this should generally ONLY be `None` during construction. |
54a0048b SL |
1078 | /// Therefore, you should generally access it via the |
1079 | /// `terminator()` or `terminator_mut()` methods. The only | |
1080 | /// exception is that certain passes, such as `simplify_cfg`, swap | |
1081 | /// out the terminator temporarily with `None` while they continue | |
1082 | /// to recurse over the set of basic blocks. | |
9cc50fc6 | 1083 | pub terminator: Option<Terminator<'tcx>>, |
54a0048b SL |
1084 | |
1085 | /// If true, this block lies on an unwind path. This is used | |
94b46f34 | 1086 | /// during codegen where distinct kinds of basic blocks may be |
54a0048b SL |
1087 | /// generated (particularly for MSVC cleanup). Unwind blocks must |
1088 | /// only branch to other unwind blocks. | |
9cc50fc6 | 1089 | pub is_cleanup: bool, |
e9174d1e SL |
1090 | } |
1091 | ||
74b04a01 | 1092 | /// Information about an assertion failure. |
3dfed10e | 1093 | #[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] |
74b04a01 XL |
1094 | pub enum AssertKind<O> { |
1095 | BoundsCheck { len: O, index: O }, | |
f035d41b XL |
1096 | Overflow(BinOp, O, O), |
1097 | OverflowNeg(O), | |
1098 | DivisionByZero(O), | |
1099 | RemainderByZero(O), | |
74b04a01 XL |
1100 | ResumedAfterReturn(GeneratorKind), |
1101 | ResumedAfterPanic(GeneratorKind), | |
1102 | } | |
1103 | ||
3dfed10e | 1104 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
f9f354fc XL |
1105 | pub enum InlineAsmOperand<'tcx> { |
1106 | In { | |
1107 | reg: InlineAsmRegOrRegClass, | |
1108 | value: Operand<'tcx>, | |
1109 | }, | |
1110 | Out { | |
1111 | reg: InlineAsmRegOrRegClass, | |
1112 | late: bool, | |
1113 | place: Option<Place<'tcx>>, | |
1114 | }, | |
1115 | InOut { | |
1116 | reg: InlineAsmRegOrRegClass, | |
1117 | late: bool, | |
1118 | in_value: Operand<'tcx>, | |
1119 | out_place: Option<Place<'tcx>>, | |
1120 | }, | |
1121 | Const { | |
1122 | value: Operand<'tcx>, | |
1123 | }, | |
1124 | SymFn { | |
1125 | value: Box<Constant<'tcx>>, | |
1126 | }, | |
1127 | SymStatic { | |
f035d41b | 1128 | def_id: DefId, |
f9f354fc XL |
1129 | }, |
1130 | } | |
1131 | ||
74b04a01 XL |
1132 | /// Type for MIR `Assert` terminator error messages. |
1133 | pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; | |
1134 | ||
83c7162d XL |
1135 | pub type Successors<'a> = |
1136 | iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>; | |
1137 | pub type SuccessorsMut<'a> = | |
1138 | iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; | |
1139 | ||
b039eaaf | 1140 | impl<'tcx> BasicBlockData<'tcx> { |
9cc50fc6 | 1141 | pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> { |
416331ca | 1142 | BasicBlockData { statements: vec![], terminator, is_cleanup: false } |
e9174d1e | 1143 | } |
9cc50fc6 SL |
1144 | |
1145 | /// Accessor for terminator. | |
1146 | /// | |
1147 | /// Terminator may not be None after construction of the basic block is complete. This accessor | |
1148 | /// provides a convenience way to reach the terminator. | |
1149 | pub fn terminator(&self) -> &Terminator<'tcx> { | |
1150 | self.terminator.as_ref().expect("invalid terminator state") | |
1151 | } | |
1152 | ||
1153 | pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { | |
1154 | self.terminator.as_mut().expect("invalid terminator state") | |
1155 | } | |
ea8adc8c | 1156 | |
94b46f34 XL |
1157 | pub fn retain_statements<F>(&mut self, mut f: F) |
1158 | where | |
0bf4aa26 | 1159 | F: FnMut(&mut Statement<'_>) -> bool, |
94b46f34 | 1160 | { |
ea8adc8c XL |
1161 | for s in &mut self.statements { |
1162 | if !f(s) { | |
0531ce1d | 1163 | s.make_nop(); |
ea8adc8c XL |
1164 | } |
1165 | } | |
1166 | } | |
ff7c6d11 | 1167 | |
0531ce1d | 1168 | pub fn expand_statements<F, I>(&mut self, mut f: F) |
94b46f34 XL |
1169 | where |
1170 | F: FnMut(&mut Statement<'tcx>) -> Option<I>, | |
1171 | I: iter::TrustedLen<Item = Statement<'tcx>>, | |
0531ce1d XL |
1172 | { |
1173 | // Gather all the iterators we'll need to splice in, and their positions. | |
1174 | let mut splices: Vec<(usize, I)> = vec![]; | |
1175 | let mut extra_stmts = 0; | |
1176 | for (i, s) in self.statements.iter_mut().enumerate() { | |
1177 | if let Some(mut new_stmts) = f(s) { | |
1178 | if let Some(first) = new_stmts.next() { | |
1179 | // We can already store the first new statement. | |
1180 | *s = first; | |
1181 | ||
1182 | // Save the other statements for optimized splicing. | |
1183 | let remaining = new_stmts.size_hint().0; | |
1184 | if remaining > 0 { | |
1185 | splices.push((i + 1 + extra_stmts, new_stmts)); | |
1186 | extra_stmts += remaining; | |
1187 | } | |
1188 | } else { | |
1189 | s.make_nop(); | |
1190 | } | |
1191 | } | |
1192 | } | |
1193 | ||
1194 | // Splice in the new statements, from the end of the block. | |
1195 | // FIXME(eddyb) This could be more efficient with a "gap buffer" | |
1196 | // where a range of elements ("gap") is left uninitialized, with | |
1197 | // splicing adding new elements to the end of that gap and moving | |
1198 | // existing elements from before the gap to the end of the gap. | |
1199 | // For now, this is safe code, emulating a gap but initializing it. | |
94b46f34 XL |
1200 | let mut gap = self.statements.len()..self.statements.len() + extra_stmts; |
1201 | self.statements.resize( | |
1202 | gap.end, | |
f9f354fc | 1203 | Statement { source_info: SourceInfo::outermost(DUMMY_SP), kind: StatementKind::Nop }, |
94b46f34 | 1204 | ); |
0531ce1d XL |
1205 | for (splice_start, new_stmts) in splices.into_iter().rev() { |
1206 | let splice_end = splice_start + new_stmts.size_hint().0; | |
1207 | while gap.end > splice_end { | |
1208 | gap.start -= 1; | |
1209 | gap.end -= 1; | |
1210 | self.statements.swap(gap.start, gap.end); | |
1211 | } | |
1212 | self.statements.splice(splice_start..splice_end, new_stmts); | |
1213 | gap.end = splice_start; | |
1214 | } | |
1215 | } | |
1216 | ||
ff7c6d11 | 1217 | pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { |
dfeec247 | 1218 | if index < self.statements.len() { &self.statements[index] } else { &self.terminator } |
ff7c6d11 | 1219 | } |
e9174d1e SL |
1220 | } |
1221 | ||
74b04a01 XL |
1222 | impl<O> AssertKind<O> { |
1223 | /// Getting a description does not require `O` to be printable, and does not | |
1224 | /// require allocation. | |
1225 | /// The caller is expected to handle `BoundsCheck` separately. | |
1226 | pub fn description(&self) -> &'static str { | |
1227 | use AssertKind::*; | |
1228 | match self { | |
f035d41b XL |
1229 | Overflow(BinOp::Add, _, _) => "attempt to add with overflow", |
1230 | Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow", | |
1231 | Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow", | |
1232 | Overflow(BinOp::Div, _, _) => "attempt to divide with overflow", | |
1233 | Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow", | |
1234 | OverflowNeg(_) => "attempt to negate with overflow", | |
1235 | Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow", | |
1236 | Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow", | |
1237 | Overflow(op, _, _) => bug!("{:?} cannot overflow", op), | |
1238 | DivisionByZero(_) => "attempt to divide by zero", | |
1239 | RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero", | |
74b04a01 XL |
1240 | ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion", |
1241 | ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion", | |
1242 | ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking", | |
1243 | ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking", | |
1244 | BoundsCheck { .. } => bug!("Unexpected AssertKind"), | |
1245 | } | |
1246 | } | |
ba9703b0 XL |
1247 | |
1248 | /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing. | |
1249 | fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result | |
1250 | where | |
1251 | O: Debug, | |
1252 | { | |
f035d41b | 1253 | use AssertKind::*; |
ba9703b0 | 1254 | match self { |
f035d41b | 1255 | BoundsCheck { ref len, ref index } => write!( |
ba9703b0 XL |
1256 | f, |
1257 | "\"index out of bounds: the len is {{}} but the index is {{}}\", {:?}, {:?}", | |
1258 | len, index | |
1259 | ), | |
f035d41b XL |
1260 | |
1261 | OverflowNeg(op) => { | |
1262 | write!(f, "\"attempt to negate {{}} which would overflow\", {:?}", op) | |
1263 | } | |
1264 | DivisionByZero(op) => write!(f, "\"attempt to divide {{}} by zero\", {:?}", op), | |
1265 | RemainderByZero(op) => write!( | |
1266 | f, | |
1267 | "\"attempt to calculate the remainder of {{}} with a divisor of zero\", {:?}", | |
1268 | op | |
1269 | ), | |
1270 | Overflow(BinOp::Add, l, r) => write!( | |
1271 | f, | |
1272 | "\"attempt to compute `{{}} + {{}}` which would overflow\", {:?}, {:?}", | |
1273 | l, r | |
1274 | ), | |
1275 | Overflow(BinOp::Sub, l, r) => write!( | |
1276 | f, | |
1277 | "\"attempt to compute `{{}} - {{}}` which would overflow\", {:?}, {:?}", | |
1278 | l, r | |
1279 | ), | |
1280 | Overflow(BinOp::Mul, l, r) => write!( | |
1281 | f, | |
1282 | "\"attempt to compute `{{}} * {{}}` which would overflow\", {:?}, {:?}", | |
1283 | l, r | |
1284 | ), | |
1285 | Overflow(BinOp::Div, l, r) => write!( | |
1286 | f, | |
1287 | "\"attempt to compute `{{}} / {{}}` which would overflow\", {:?}, {:?}", | |
1288 | l, r | |
1289 | ), | |
1290 | Overflow(BinOp::Rem, l, r) => write!( | |
1291 | f, | |
1292 | "\"attempt to compute the remainder of `{{}} % {{}}` which would overflow\", {:?}, {:?}", | |
1293 | l, r | |
1294 | ), | |
1295 | Overflow(BinOp::Shr, _, r) => { | |
1296 | write!(f, "\"attempt to shift right by {{}} which would overflow\", {:?}", r) | |
1297 | } | |
1298 | Overflow(BinOp::Shl, _, r) => { | |
1299 | write!(f, "\"attempt to shift left by {{}} which would overflow\", {:?}", r) | |
1300 | } | |
ba9703b0 XL |
1301 | _ => write!(f, "\"{}\"", self.description()), |
1302 | } | |
1303 | } | |
74b04a01 XL |
1304 | } |
1305 | ||
1306 | impl<O: fmt::Debug> fmt::Debug for AssertKind<O> { | |
1307 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
1308 | use AssertKind::*; | |
1309 | match self { | |
1310 | BoundsCheck { ref len, ref index } => { | |
1311 | write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index) | |
1312 | } | |
f035d41b XL |
1313 | OverflowNeg(op) => write!(f, "attempt to negate {:#?} which would overflow", op), |
1314 | DivisionByZero(op) => write!(f, "attempt to divide {:#?} by zero", op), | |
1315 | RemainderByZero(op) => { | |
1316 | write!(f, "attempt to calculate the remainder of {:#?} with a divisor of zero", op) | |
416331ca | 1317 | } |
f035d41b XL |
1318 | Overflow(BinOp::Add, l, r) => { |
1319 | write!(f, "attempt to compute `{:#?} + {:#?}` which would overflow", l, r) | |
e9174d1e | 1320 | } |
f035d41b XL |
1321 | Overflow(BinOp::Sub, l, r) => { |
1322 | write!(f, "attempt to compute `{:#?} - {:#?}` which would overflow", l, r) | |
94b46f34 | 1323 | } |
f035d41b XL |
1324 | Overflow(BinOp::Mul, l, r) => { |
1325 | write!(f, "attempt to compute `{:#?} * {:#?}` which would overflow", l, r) | |
f9f354fc | 1326 | } |
f035d41b XL |
1327 | Overflow(BinOp::Div, l, r) => { |
1328 | write!(f, "attempt to compute `{:#?} / {:#?}` which would overflow", l, r) | |
9cc50fc6 | 1329 | } |
f035d41b XL |
1330 | Overflow(BinOp::Rem, l, r) => write!( |
1331 | f, | |
1332 | "attempt to compute the remainder of `{:#?} % {:#?}` which would overflow", | |
1333 | l, r | |
1334 | ), | |
1335 | Overflow(BinOp::Shr, _, r) => { | |
1336 | write!(f, "attempt to shift right by {:#?} which would overflow", r) | |
94b46f34 | 1337 | } |
f035d41b XL |
1338 | Overflow(BinOp::Shl, _, r) => { |
1339 | write!(f, "attempt to shift left by {:#?} which would overflow", r) | |
3157f602 | 1340 | } |
f035d41b | 1341 | _ => write!(f, "{}", self.description()), |
9cc50fc6 SL |
1342 | } |
1343 | } | |
e9174d1e SL |
1344 | } |
1345 | ||
e9174d1e SL |
1346 | /////////////////////////////////////////////////////////////////////////// |
1347 | // Statements | |
1348 | ||
3dfed10e | 1349 | #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
b039eaaf | 1350 | pub struct Statement<'tcx> { |
3157f602 | 1351 | pub source_info: SourceInfo, |
b039eaaf | 1352 | pub kind: StatementKind<'tcx>, |
e9174d1e SL |
1353 | } |
1354 | ||
a1dfa0c6 XL |
1355 | // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. |
1356 | #[cfg(target_arch = "x86_64")] | |
e1599b0c | 1357 | static_assert_size!(Statement<'_>, 32); |
a1dfa0c6 | 1358 | |
e1599b0c | 1359 | impl Statement<'_> { |
9e0c209e SL |
1360 | /// Changes a statement to a nop. This is both faster than deleting instructions and avoids |
1361 | /// invalidating statement indices in `Location`s. | |
1362 | pub fn make_nop(&mut self) { | |
1363 | self.kind = StatementKind::Nop | |
1364 | } | |
0531ce1d XL |
1365 | |
1366 | /// Changes a statement to a nop and returns the original statement. | |
1367 | pub fn replace_nop(&mut self) -> Self { | |
1368 | Statement { | |
1369 | source_info: self.source_info, | |
94b46f34 | 1370 | kind: mem::replace(&mut self.kind, StatementKind::Nop), |
0531ce1d XL |
1371 | } |
1372 | } | |
9e0c209e SL |
1373 | } |
1374 | ||
3dfed10e | 1375 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
b039eaaf | 1376 | pub enum StatementKind<'tcx> { |
ff7c6d11 | 1377 | /// Write the RHS Rvalue to the LHS Place. |
e1599b0c | 1378 | Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), |
5bcae85e | 1379 | |
94b46f34 | 1380 | /// This represents all the reading that a pattern match may do |
0731742a | 1381 | /// (e.g., inspecting constants and discriminant values), and the |
0bf4aa26 XL |
1382 | /// kind of pattern it comes from. This is in order to adapt potential |
1383 | /// error messages to these specific patterns. | |
0731742a XL |
1384 | /// |
1385 | /// Note that this also is emitted for regular `let` bindings to ensure that locals that are | |
9fa01778 | 1386 | /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` |
e1599b0c | 1387 | FakeRead(FakeReadCause, Box<Place<'tcx>>), |
94b46f34 | 1388 | |
ff7c6d11 | 1389 | /// Write the discriminant for a variant to the enum Place. |
e1599b0c | 1390 | SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx }, |
5bcae85e SL |
1391 | |
1392 | /// Start a live range for the storage of the local. | |
ea8adc8c | 1393 | StorageLive(Local), |
5bcae85e SL |
1394 | |
1395 | /// End the current live range for the storage of the local. | |
ea8adc8c | 1396 | StorageDead(Local), |
9e0c209e | 1397 | |
532ac7d7 XL |
1398 | /// Executes a piece of inline Assembly. Stored in a Box to keep the size |
1399 | /// of `StatementKind` low. | |
ba9703b0 | 1400 | LlvmInlineAsm(Box<LlvmInlineAsm<'tcx>>), |
8bb4bdeb | 1401 | |
9fa01778 | 1402 | /// Retag references in the given place, ensuring they got fresh tags. This is |
a1dfa0c6 XL |
1403 | /// part of the Stacked Borrows model. These statements are currently only interpreted |
1404 | /// by miri and only generated when "-Z mir-emit-retag" is passed. | |
1405 | /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> | |
1406 | /// for more details. | |
e1599b0c | 1407 | Retag(RetagKind, Box<Place<'tcx>>), |
041b39d2 | 1408 | |
b7449926 XL |
1409 | /// Encodes a user's type ascription. These need to be preserved |
1410 | /// intact so that NLL can respect them. For example: | |
0531ce1d | 1411 | /// |
b7449926 | 1412 | /// let a: T = y; |
0531ce1d | 1413 | /// |
b7449926 XL |
1414 | /// The effect of this annotation is to relate the type `T_y` of the place `y` |
1415 | /// to the user-given type `T`. The effect depends on the specified variance: | |
0531ce1d | 1416 | /// |
b7449926 XL |
1417 | /// - `Covariant` -- requires that `T_y <: T` |
1418 | /// - `Contravariant` -- requires that `T_y :> T` | |
1419 | /// - `Invariant` -- requires that `T_y == T` | |
1420 | /// - `Bivariant` -- no effect | |
e1599b0c | 1421 | AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), |
0531ce1d | 1422 | |
3dfed10e XL |
1423 | /// Marks the start of a "coverage region", injected with '-Zinstrument-coverage'. A |
1424 | /// `CoverageInfo` statement carries metadata about the coverage region, used to inject a coverage | |
1425 | /// map into the binary. The `Counter` kind also generates executable code, to increment a | |
1426 | /// counter varible at runtime, each time the code region is executed. | |
1427 | Coverage(Box<Coverage>), | |
1428 | ||
9e0c209e SL |
1429 | /// No-op. Useful for deleting instructions without affecting statement indices. |
1430 | Nop, | |
e9174d1e SL |
1431 | } |
1432 | ||
e1599b0c | 1433 | /// Describes what kind of retag is to be performed. |
3dfed10e | 1434 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, HashStable)] |
0731742a | 1435 | pub enum RetagKind { |
e1599b0c | 1436 | /// The initial retag when entering a function. |
0731742a | 1437 | FnEntry, |
e1599b0c | 1438 | /// Retag preparing for a two-phase borrow. |
0731742a | 1439 | TwoPhase, |
e1599b0c | 1440 | /// Retagging raw pointers. |
0731742a | 1441 | Raw, |
e1599b0c | 1442 | /// A "normal" retag. |
0731742a XL |
1443 | Default, |
1444 | } | |
1445 | ||
e1599b0c | 1446 | /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. |
3dfed10e | 1447 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, HashStable, PartialEq)] |
0bf4aa26 | 1448 | pub enum FakeReadCause { |
9fa01778 XL |
1449 | /// Inject a fake read of the borrowed input at the end of each guards |
1450 | /// code. | |
0bf4aa26 | 1451 | /// |
9fa01778 XL |
1452 | /// This should ensure that you cannot change the variant for an enum while |
1453 | /// you are in the midst of matching on it. | |
0bf4aa26 XL |
1454 | ForMatchGuard, |
1455 | ||
1456 | /// `let x: !; match x {}` doesn't generate any read of x so we need to | |
1457 | /// generate a read of x to check that it is initialized and safe. | |
1458 | ForMatchedPlace, | |
1459 | ||
9fa01778 XL |
1460 | /// A fake read of the RefWithinGuard version of a bind-by-value variable |
1461 | /// in a match guard to ensure that it's value hasn't change by the time | |
1462 | /// we create the OutsideGuard version. | |
1463 | ForGuardBinding, | |
1464 | ||
0bf4aa26 XL |
1465 | /// Officially, the semantics of |
1466 | /// | |
1467 | /// `let pattern = <expr>;` | |
1468 | /// | |
1469 | /// is that `<expr>` is evaluated into a temporary and then this temporary is | |
1470 | /// into the pattern. | |
1471 | /// | |
1472 | /// However, if we see the simple pattern `let var = <expr>`, we optimize this to | |
1473 | /// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable, | |
1474 | /// but in some cases it can affect the borrow checker, as in #53695. | |
1475 | /// Therefore, we insert a "fake read" here to ensure that we get | |
1476 | /// appropriate errors. | |
1477 | ForLet, | |
60c5eb7d XL |
1478 | |
1479 | /// If we have an index expression like | |
1480 | /// | |
1481 | /// (*x)[1][{ x = y; 4}] | |
1482 | /// | |
1483 | /// then the first bounds check is invalidated when we evaluate the second | |
1484 | /// index expression. Thus we create a fake borrow of `x` across the second | |
1485 | /// indexer, which will cause a borrow check error. | |
1486 | ForIndex, | |
0bf4aa26 XL |
1487 | } |
1488 | ||
3dfed10e | 1489 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
ba9703b0 XL |
1490 | pub struct LlvmInlineAsm<'tcx> { |
1491 | pub asm: hir::LlvmInlineAsmInner, | |
532ac7d7 XL |
1492 | pub outputs: Box<[Place<'tcx>]>, |
1493 | pub inputs: Box<[(Span, Operand<'tcx>)]>, | |
1494 | } | |
1495 | ||
e1599b0c | 1496 | impl Debug for Statement<'_> { |
0bf4aa26 | 1497 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
1498 | use self::StatementKind::*; |
1499 | match self.kind { | |
dfeec247 | 1500 | Assign(box (ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv), |
0bf4aa26 | 1501 | FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place), |
416331ca XL |
1502 | Retag(ref kind, ref place) => write!( |
1503 | fmt, | |
1504 | "Retag({}{:?})", | |
1505 | match kind { | |
1506 | RetagKind::FnEntry => "[fn entry] ", | |
1507 | RetagKind::TwoPhase => "[2phase] ", | |
1508 | RetagKind::Raw => "[raw] ", | |
1509 | RetagKind::Default => "", | |
1510 | }, | |
1511 | place, | |
1512 | ), | |
ff7c6d11 XL |
1513 | StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place), |
1514 | StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place), | |
416331ca XL |
1515 | SetDiscriminant { ref place, variant_index } => { |
1516 | write!(fmt, "discriminant({:?}) = {:?}", place, variant_index) | |
1517 | } | |
ba9703b0 XL |
1518 | LlvmInlineAsm(ref asm) => { |
1519 | write!(fmt, "llvm_asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs) | |
416331ca | 1520 | } |
dfeec247 | 1521 | AscribeUserType(box (ref place, ref c_ty), ref variance) => { |
b7449926 | 1522 | write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) |
94b46f34 | 1523 | } |
3dfed10e | 1524 | Coverage(box ref coverage) => write!(fmt, "{:?}", coverage), |
9e0c209e | 1525 | Nop => write!(fmt, "nop"), |
e9174d1e SL |
1526 | } |
1527 | } | |
1528 | } | |
54a0048b | 1529 | |
3dfed10e XL |
1530 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
1531 | pub struct Coverage { | |
1532 | pub kind: CoverageKind, | |
1533 | pub code_region: CodeRegion, | |
1534 | } | |
1535 | ||
e9174d1e | 1536 | /////////////////////////////////////////////////////////////////////////// |
ff7c6d11 | 1537 | // Places |
e9174d1e SL |
1538 | |
1539 | /// A path to a value; something that can be evaluated without | |
1540 | /// changing or disturbing program state. | |
3dfed10e | 1541 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)] |
416331ca | 1542 | pub struct Place<'tcx> { |
dfeec247 | 1543 | pub local: Local, |
532ac7d7 XL |
1544 | |
1545 | /// projection out of a place (access a field, deref a pointer, etc) | |
e74abb32 | 1546 | pub projection: &'tcx List<PlaceElem<'tcx>>, |
532ac7d7 XL |
1547 | } |
1548 | ||
60c5eb7d | 1549 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
3dfed10e | 1550 | #[derive(TyEncodable, TyDecodable, HashStable)] |
532ac7d7 | 1551 | pub enum ProjectionElem<V, T> { |
e9174d1e | 1552 | Deref, |
3b2f2976 | 1553 | Field(Field, T), |
e9174d1e SL |
1554 | Index(V), |
1555 | ||
7453a54e SL |
1556 | /// These indices are generated by slice patterns. Easiest to explain |
1557 | /// by example: | |
1558 | /// | |
1559 | /// ``` | |
1560 | /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, | |
1561 | /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, | |
1562 | /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, | |
1563 | /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, | |
1564 | /// ``` | |
e9174d1e | 1565 | ConstantIndex { |
7453a54e SL |
1566 | /// index or -index (in Python terms), depending on from_end |
1567 | offset: u32, | |
60c5eb7d XL |
1568 | /// The thing being indexed must be at least this long. For arrays this |
1569 | /// is always the exact length. | |
7453a54e | 1570 | min_length: u32, |
60c5eb7d XL |
1571 | /// Counting backwards from end? This is always false when indexing an |
1572 | /// array. | |
7453a54e | 1573 | from_end: bool, |
e9174d1e SL |
1574 | }, |
1575 | ||
3157f602 XL |
1576 | /// These indices are generated by slice patterns. |
1577 | /// | |
60c5eb7d XL |
1578 | /// If `from_end` is true `slice[from..slice.len() - to]`. |
1579 | /// Otherwise `array[from..to]`. | |
3157f602 XL |
1580 | Subslice { |
1581 | from: u32, | |
1582 | to: u32, | |
60c5eb7d XL |
1583 | /// Whether `to` counts from the start or end of the array/slice. |
1584 | /// For `PlaceElem`s this is `true` if and only if the base is a slice. | |
1585 | /// For `ProjectionKind`, this can also be `true` for arrays. | |
1586 | from_end: bool, | |
3157f602 XL |
1587 | }, |
1588 | ||
7453a54e SL |
1589 | /// "Downcast" to a variant of an ADT. Currently, we only introduce |
1590 | /// this for ADTs with more than one variant. It may be better to | |
1591 | /// just introduce it always, or always for enums. | |
532ac7d7 XL |
1592 | /// |
1593 | /// The included Symbol is the name of the variant, used for printing MIR. | |
1594 | Downcast(Option<Symbol>, VariantIdx), | |
e9174d1e SL |
1595 | } |
1596 | ||
e1599b0c XL |
1597 | impl<V, T> ProjectionElem<V, T> { |
1598 | /// Returns `true` if the target of this projection may refer to a different region of memory | |
1599 | /// than the base. | |
1600 | fn is_indirect(&self) -> bool { | |
1601 | match self { | |
1602 | Self::Deref => true, | |
1603 | ||
dfeec247 | 1604 | Self::Field(_, _) |
e1599b0c XL |
1605 | | Self::Index(_) |
1606 | | Self::ConstantIndex { .. } | |
1607 | | Self::Subslice { .. } | |
dfeec247 | 1608 | | Self::Downcast(_, _) => false, |
e1599b0c XL |
1609 | } |
1610 | } | |
1611 | } | |
1612 | ||
ff7c6d11 | 1613 | /// Alias for projections as they appear in places, where the base is a place |
ea8adc8c | 1614 | /// and the index is a local. |
532ac7d7 | 1615 | pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; |
e9174d1e | 1616 | |
48663c56 XL |
1617 | // At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. |
1618 | #[cfg(target_arch = "x86_64")] | |
1619 | static_assert_size!(PlaceElem<'_>, 16); | |
a1dfa0c6 | 1620 | |
0bf4aa26 XL |
1621 | /// Alias for projections as they appear in `UserTypeProjection`, where we |
1622 | /// need neither the `V` parameter for `Index` nor the `T` for `Field`. | |
532ac7d7 | 1623 | pub type ProjectionKind = ProjectionElem<(), ()>; |
0bf4aa26 | 1624 | |
e74abb32 | 1625 | rustc_index::newtype_index! { |
b7449926 | 1626 | pub struct Field { |
532ac7d7 | 1627 | derive [HashStable] |
b7449926 XL |
1628 | DEBUG_FORMAT = "field[{}]" |
1629 | } | |
1630 | } | |
e9174d1e | 1631 | |
416331ca | 1632 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
74b04a01 XL |
1633 | pub struct PlaceRef<'tcx> { |
1634 | pub local: Local, | |
1635 | pub projection: &'tcx [PlaceElem<'tcx>], | |
416331ca XL |
1636 | } |
1637 | ||
ff7c6d11 | 1638 | impl<'tcx> Place<'tcx> { |
e74abb32 | 1639 | // FIXME change this to a const fn by also making List::empty a const fn. |
e1599b0c | 1640 | pub fn return_place() -> Place<'tcx> { |
dfeec247 | 1641 | Place { local: RETURN_PLACE, projection: List::empty() } |
e9174d1e | 1642 | } |
0bf4aa26 | 1643 | |
e1599b0c XL |
1644 | /// Returns `true` if this `Place` contains a `Deref` projection. |
1645 | /// | |
1646 | /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the | |
1647 | /// same region of memory as its base. | |
1648 | pub fn is_indirect(&self) -> bool { | |
1649 | self.projection.iter().any(|elem| elem.is_indirect()) | |
1650 | } | |
1651 | ||
9fa01778 | 1652 | /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or |
0bf4aa26 | 1653 | /// a single deref of a local. |
9fa01778 XL |
1654 | // |
1655 | // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? | |
dc9dc135 | 1656 | pub fn local_or_deref_local(&self) -> Option<Local> { |
e74abb32 | 1657 | match self.as_ref() { |
74b04a01 XL |
1658 | PlaceRef { local, projection: [] } |
1659 | | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), | |
0bf4aa26 XL |
1660 | _ => None, |
1661 | } | |
1662 | } | |
1663 | ||
e1599b0c XL |
1664 | /// If this place represents a local variable like `_X` with no |
1665 | /// projections, return `Some(_X)`. | |
1666 | pub fn as_local(&self) -> Option<Local> { | |
e74abb32 | 1667 | self.as_ref().as_local() |
416331ca XL |
1668 | } |
1669 | ||
74b04a01 XL |
1670 | pub fn as_ref(&self) -> PlaceRef<'tcx> { |
1671 | PlaceRef { local: self.local, projection: &self.projection } | |
0bf4aa26 | 1672 | } |
e9174d1e SL |
1673 | } |
1674 | ||
dc9dc135 XL |
1675 | impl From<Local> for Place<'_> { |
1676 | fn from(local: Local) -> Self { | |
dfeec247 | 1677 | Place { local, projection: List::empty() } |
dc9dc135 XL |
1678 | } |
1679 | } | |
1680 | ||
74b04a01 | 1681 | impl<'tcx> PlaceRef<'tcx> { |
416331ca XL |
1682 | /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or |
1683 | /// a single deref of a local. | |
1684 | // | |
1685 | // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? | |
1686 | pub fn local_or_deref_local(&self) -> Option<Local> { | |
74b04a01 | 1687 | match *self { |
dfeec247 | 1688 | PlaceRef { local, projection: [] } |
74b04a01 | 1689 | | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), |
416331ca XL |
1690 | _ => None, |
1691 | } | |
1692 | } | |
e74abb32 XL |
1693 | |
1694 | /// If this place represents a local variable like `_X` with no | |
1695 | /// projections, return `Some(_X)`. | |
1696 | pub fn as_local(&self) -> Option<Local> { | |
74b04a01 XL |
1697 | match *self { |
1698 | PlaceRef { local, projection: [] } => Some(local), | |
e74abb32 XL |
1699 | _ => None, |
1700 | } | |
1701 | } | |
416331ca XL |
1702 | } |
1703 | ||
e1599b0c | 1704 | impl Debug for Place<'_> { |
0bf4aa26 | 1705 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e1599b0c XL |
1706 | for elem in self.projection.iter().rev() { |
1707 | match elem { | |
1708 | ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { | |
1709 | write!(fmt, "(").unwrap(); | |
1710 | } | |
1711 | ProjectionElem::Deref => { | |
1712 | write!(fmt, "(*").unwrap(); | |
94b46f34 | 1713 | } |
e1599b0c XL |
1714 | ProjectionElem::Index(_) |
1715 | | ProjectionElem::ConstantIndex { .. } | |
1716 | | ProjectionElem::Subslice { .. } => {} | |
48663c56 | 1717 | } |
e1599b0c | 1718 | } |
48663c56 | 1719 | |
dfeec247 | 1720 | write!(fmt, "{:?}", self.local)?; |
48663c56 | 1721 | |
e1599b0c XL |
1722 | for elem in self.projection.iter() { |
1723 | match elem { | |
1724 | ProjectionElem::Downcast(Some(name), _index) => { | |
1725 | write!(fmt, " as {})", name)?; | |
1726 | } | |
1727 | ProjectionElem::Downcast(None, index) => { | |
1728 | write!(fmt, " as variant#{:?})", index)?; | |
1729 | } | |
1730 | ProjectionElem::Deref => { | |
1731 | write!(fmt, ")")?; | |
1732 | } | |
1733 | ProjectionElem::Field(field, ty) => { | |
1734 | write!(fmt, ".{:?}: {:?})", field.index(), ty)?; | |
1735 | } | |
1736 | ProjectionElem::Index(ref index) => { | |
1737 | write!(fmt, "[{:?}]", index)?; | |
1738 | } | |
1739 | ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { | |
1740 | write!(fmt, "[{:?} of {:?}]", offset, min_length)?; | |
1741 | } | |
1742 | ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { | |
1743 | write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; | |
1744 | } | |
f9f354fc | 1745 | ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => { |
e1599b0c XL |
1746 | write!(fmt, "[{:?}:]", from)?; |
1747 | } | |
f9f354fc | 1748 | ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => { |
e1599b0c XL |
1749 | write!(fmt, "[:-{:?}]", to)?; |
1750 | } | |
60c5eb7d | 1751 | ProjectionElem::Subslice { from, to, from_end: true } => { |
e1599b0c | 1752 | write!(fmt, "[{:?}:-{:?}]", from, to)?; |
94b46f34 | 1753 | } |
60c5eb7d XL |
1754 | ProjectionElem::Subslice { from, to, from_end: false } => { |
1755 | write!(fmt, "[{:?}..{:?}]", from, to)?; | |
1756 | } | |
48663c56 | 1757 | } |
e1599b0c | 1758 | } |
48663c56 | 1759 | |
e1599b0c | 1760 | Ok(()) |
e9174d1e SL |
1761 | } |
1762 | } | |
1763 | ||
54a0048b SL |
1764 | /////////////////////////////////////////////////////////////////////////// |
1765 | // Scopes | |
1766 | ||
e74abb32 | 1767 | rustc_index::newtype_index! { |
b7449926 | 1768 | pub struct SourceScope { |
532ac7d7 | 1769 | derive [HashStable] |
abe05a73 | 1770 | DEBUG_FORMAT = "scope[{}]", |
94b46f34 | 1771 | const OUTERMOST_SOURCE_SCOPE = 0, |
b7449926 XL |
1772 | } |
1773 | } | |
54a0048b | 1774 | |
3dfed10e | 1775 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] |
94b46f34 | 1776 | pub struct SourceScopeData { |
a7813a04 | 1777 | pub span: Span, |
94b46f34 | 1778 | pub parent_scope: Option<SourceScope>, |
60c5eb7d XL |
1779 | |
1780 | /// Crate-local information for this source scope, that can't (and | |
1781 | /// needn't) be tracked across crates. | |
1782 | pub local_data: ClearCrossCrate<SourceScopeLocalData>, | |
94b46f34 XL |
1783 | } |
1784 | ||
3dfed10e | 1785 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] |
94b46f34 | 1786 | pub struct SourceScopeLocalData { |
e1599b0c | 1787 | /// An `HirId` with lint levels equivalent to this scope's lint levels. |
532ac7d7 | 1788 | pub lint_root: hir::HirId, |
94b46f34 XL |
1789 | /// The unsafe block that contains this node. |
1790 | pub safety: Safety, | |
54a0048b SL |
1791 | } |
1792 | ||
e9174d1e SL |
1793 | /////////////////////////////////////////////////////////////////////////// |
1794 | // Operands | |
54a0048b | 1795 | |
0bf4aa26 XL |
1796 | /// These are values that can appear inside an rvalue. They are intentionally |
1797 | /// limited to prevent rvalues from being nested in one another. | |
3dfed10e | 1798 | #[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable)] |
b039eaaf | 1799 | pub enum Operand<'tcx> { |
ff7c6d11 XL |
1800 | /// Copy: The value must be available for use afterwards. |
1801 | /// | |
1802 | /// This implies that the type of the place must be `Copy`; this is true | |
1803 | /// by construction during build, but also checked by the MIR type checker. | |
1804 | Copy(Place<'tcx>), | |
b7449926 | 1805 | |
ff7c6d11 XL |
1806 | /// Move: The value (including old borrows of it) will not be used again. |
1807 | /// | |
1808 | /// Safe for values of all types (modulo future developments towards `?Move`). | |
1809 | /// Correct usage patterns are enforced by the borrow checker for safe code. | |
1810 | /// `Copy` may be converted to `Move` to enable "last-use" optimizations. | |
1811 | Move(Place<'tcx>), | |
b7449926 XL |
1812 | |
1813 | /// Synthesizes a constant value. | |
cc61c64b | 1814 | Constant(Box<Constant<'tcx>>), |
e9174d1e SL |
1815 | } |
1816 | ||
b039eaaf | 1817 | impl<'tcx> Debug for Operand<'tcx> { |
0bf4aa26 | 1818 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
1819 | use self::Operand::*; |
1820 | match *self { | |
1821 | Constant(ref a) => write!(fmt, "{:?}", a), | |
ff7c6d11 XL |
1822 | Copy(ref place) => write!(fmt, "{:?}", place), |
1823 | Move(ref place) => write!(fmt, "move {:?}", place), | |
e9174d1e SL |
1824 | } |
1825 | } | |
1826 | } | |
1827 | ||
cc61c64b | 1828 | impl<'tcx> Operand<'tcx> { |
b7449926 | 1829 | /// Convenience helper to make a constant that refers to the fn |
9fa01778 | 1830 | /// with given `DefId` and substs. Since this is used to synthesize |
b7449926 | 1831 | /// MIR, assumes `user_ty` is None. |
dc9dc135 XL |
1832 | pub fn function_handle( |
1833 | tcx: TyCtxt<'tcx>, | |
cc61c64b | 1834 | def_id: DefId, |
532ac7d7 | 1835 | substs: SubstsRef<'tcx>, |
cc61c64b XL |
1836 | span: Span, |
1837 | ) -> Self { | |
ea8adc8c | 1838 | let ty = tcx.type_of(def_id).subst(tcx, substs); |
cc61c64b | 1839 | Operand::Constant(box Constant { |
041b39d2 | 1840 | span, |
b7449926 | 1841 | user_ty: None, |
dc9dc135 | 1842 | literal: ty::Const::zero_sized(tcx, ty), |
cc61c64b XL |
1843 | }) |
1844 | } | |
1845 | ||
f035d41b XL |
1846 | /// Convenience helper to make a literal-like constant from a given scalar value. |
1847 | /// Since this is used to synthesize MIR, assumes `user_ty` is None. | |
1848 | pub fn const_from_scalar( | |
1849 | tcx: TyCtxt<'tcx>, | |
1850 | ty: Ty<'tcx>, | |
1851 | val: Scalar, | |
1852 | span: Span, | |
1853 | ) -> Operand<'tcx> { | |
1854 | debug_assert!({ | |
1855 | let param_env_and_ty = ty::ParamEnv::empty().and(ty); | |
1856 | let type_size = tcx | |
1857 | .layout_of(param_env_and_ty) | |
1858 | .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) | |
1859 | .size; | |
1860 | let scalar_size = abi::Size::from_bytes(match val { | |
1861 | Scalar::Raw { size, .. } => size, | |
1862 | _ => panic!("Invalid scalar type {:?}", val), | |
1863 | }); | |
1864 | scalar_size == type_size | |
1865 | }); | |
1866 | Operand::Constant(box Constant { | |
1867 | span, | |
1868 | user_ty: None, | |
1869 | literal: ty::Const::from_scalar(tcx, val, ty), | |
1870 | }) | |
1871 | } | |
1872 | ||
1873 | /// Convenience helper to make a `Scalar` from the given `Operand`, assuming that `Operand` | |
1874 | /// wraps a constant literal value. Panics if this is not the case. | |
1875 | pub fn scalar_from_const(operand: &Operand<'tcx>) -> Scalar { | |
1876 | match operand { | |
1877 | Operand::Constant(constant) => match constant.literal.val.try_to_scalar() { | |
1878 | Some(scalar) => scalar, | |
1879 | _ => panic!("{:?}: Scalar value expected", constant.literal.val), | |
1880 | }, | |
1881 | _ => panic!("{:?}: Constant expected", operand), | |
1882 | } | |
1883 | } | |
1884 | ||
3dfed10e XL |
1885 | /// Convenience helper to make a literal-like constant from a given `&str` slice. |
1886 | /// Since this is used to synthesize MIR, assumes `user_ty` is None. | |
1887 | pub fn const_from_str(tcx: TyCtxt<'tcx>, val: &str, span: Span) -> Operand<'tcx> { | |
1888 | let tcx = tcx; | |
1889 | let allocation = Allocation::from_byte_aligned_bytes(val.as_bytes()); | |
1890 | let allocation = tcx.intern_const_alloc(allocation); | |
1891 | let const_val = ConstValue::Slice { data: allocation, start: 0, end: val.len() }; | |
1892 | let ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.types.str_); | |
1893 | Operand::Constant(box Constant { | |
1894 | span, | |
1895 | user_ty: None, | |
1896 | literal: ty::Const::from_value(tcx, const_val, ty), | |
1897 | }) | |
1898 | } | |
1899 | ||
1900 | /// Convenience helper to make a `ConstValue` from the given `Operand`, assuming that `Operand` | |
1901 | /// wraps a constant value (such as a `&str` slice). Panics if this is not the case. | |
1902 | pub fn value_from_const(operand: &Operand<'tcx>) -> ConstValue<'tcx> { | |
1903 | match operand { | |
1904 | Operand::Constant(constant) => match constant.literal.val.try_to_value() { | |
1905 | Some(const_value) => const_value, | |
1906 | _ => panic!("{:?}: ConstValue expected", constant.literal.val), | |
1907 | }, | |
1908 | _ => panic!("{:?}: Constant expected", operand), | |
1909 | } | |
1910 | } | |
1911 | ||
ff7c6d11 XL |
1912 | pub fn to_copy(&self) -> Self { |
1913 | match *self { | |
1914 | Operand::Copy(_) | Operand::Constant(_) => self.clone(), | |
dfeec247 | 1915 | Operand::Move(place) => Operand::Copy(place), |
ff7c6d11 XL |
1916 | } |
1917 | } | |
74b04a01 XL |
1918 | |
1919 | /// Returns the `Place` that is the target of this `Operand`, or `None` if this `Operand` is a | |
1920 | /// constant. | |
ba9703b0 | 1921 | pub fn place(&self) -> Option<Place<'tcx>> { |
74b04a01 | 1922 | match self { |
ba9703b0 | 1923 | Operand::Copy(place) | Operand::Move(place) => Some(*place), |
74b04a01 XL |
1924 | Operand::Constant(_) => None, |
1925 | } | |
1926 | } | |
cc61c64b XL |
1927 | } |
1928 | ||
e9174d1e | 1929 | /////////////////////////////////////////////////////////////////////////// |
7453a54e | 1930 | /// Rvalues |
e9174d1e | 1931 | |
3dfed10e | 1932 | #[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] |
b039eaaf | 1933 | pub enum Rvalue<'tcx> { |
7453a54e | 1934 | /// x (either a move or copy, depending on type of x) |
b039eaaf | 1935 | Use(Operand<'tcx>), |
e9174d1e | 1936 | |
7453a54e | 1937 | /// [x; 32] |
ba9703b0 | 1938 | Repeat(Operand<'tcx>, &'tcx ty::Const<'tcx>), |
e9174d1e | 1939 | |
7453a54e | 1940 | /// &x or &mut x |
ff7c6d11 | 1941 | Ref(Region<'tcx>, BorrowKind, Place<'tcx>), |
e9174d1e | 1942 | |
f9f354fc XL |
1943 | /// Accessing a thread local static. This is inherently a runtime operation, even if llvm |
1944 | /// treats it as an access to a static. This `Rvalue` yields a reference to the thread local | |
1945 | /// static. | |
1946 | ThreadLocalRef(DefId), | |
1947 | ||
dfeec247 XL |
1948 | /// Create a raw pointer to the given place |
1949 | /// Can be generated by raw address of expressions (`&raw const x`), | |
1950 | /// or when casting a reference to a raw pointer. | |
1951 | AddressOf(Mutability, Place<'tcx>), | |
1952 | ||
f9f354fc | 1953 | /// length of a `[X]` or `[X;n]` value |
ff7c6d11 | 1954 | Len(Place<'tcx>), |
e9174d1e | 1955 | |
b039eaaf | 1956 | Cast(CastKind, Operand<'tcx>, Ty<'tcx>), |
e9174d1e | 1957 | |
b039eaaf | 1958 | BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), |
3157f602 | 1959 | CheckedBinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), |
e9174d1e | 1960 | |
7cac9316 | 1961 | NullaryOp(NullOp, Ty<'tcx>), |
b039eaaf | 1962 | UnaryOp(UnOp, Operand<'tcx>), |
e9174d1e | 1963 | |
8bb4bdeb XL |
1964 | /// Read the discriminant of an ADT. |
1965 | /// | |
0731742a | 1966 | /// Undefined (i.e., no effort is made to make it defined, but there’s no reason why it cannot |
8bb4bdeb | 1967 | /// be defined to return, say, a 0) if ADT is not an enum. |
ff7c6d11 | 1968 | Discriminant(Place<'tcx>), |
8bb4bdeb | 1969 | |
9fa01778 | 1970 | /// Creates an aggregate value, like a tuple or struct. This is |
7453a54e SL |
1971 | /// only needed because we want to distinguish `dest = Foo { x: |
1972 | /// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case | |
1973 | /// that `Foo` has a destructor. These rvalues can be optimized | |
1974 | /// away after type-checking and before lowering. | |
cc61c64b | 1975 | Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), |
e9174d1e SL |
1976 | } |
1977 | ||
3dfed10e | 1978 | #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] |
e9174d1e SL |
1979 | pub enum CastKind { |
1980 | Misc, | |
48663c56 | 1981 | Pointer(PointerCast), |
e9174d1e SL |
1982 | } |
1983 | ||
3dfed10e | 1984 | #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] |
b039eaaf | 1985 | pub enum AggregateKind<'tcx> { |
8bb4bdeb XL |
1986 | /// The type is of the element |
1987 | Array(Ty<'tcx>), | |
e9174d1e | 1988 | Tuple, |
ff7c6d11 | 1989 | |
2c00a5a8 XL |
1990 | /// The second field is the variant index. It's equal to 0 for struct |
1991 | /// and union expressions. The fourth field is | |
ff7c6d11 | 1992 | /// active field number and is present only for union expressions |
0731742a | 1993 | /// -- e.g., for a union expression `SomeUnion { c: .. }`, the |
ff7c6d11 | 1994 | /// active field index would identity the field `c` |
416331ca | 1995 | Adt(&'tcx AdtDef, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), |
ff7c6d11 | 1996 | |
e74abb32 | 1997 | Closure(DefId, SubstsRef<'tcx>), |
60c5eb7d | 1998 | Generator(DefId, SubstsRef<'tcx>, hir::Movability), |
e9174d1e SL |
1999 | } |
2000 | ||
3dfed10e | 2001 | #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] |
e9174d1e SL |
2002 | pub enum BinOp { |
2003 | /// The `+` operator (addition) | |
2004 | Add, | |
2005 | /// The `-` operator (subtraction) | |
2006 | Sub, | |
2007 | /// The `*` operator (multiplication) | |
2008 | Mul, | |
2009 | /// The `/` operator (division) | |
2010 | Div, | |
2011 | /// The `%` operator (modulus) | |
2012 | Rem, | |
2013 | /// The `^` operator (bitwise xor) | |
2014 | BitXor, | |
2015 | /// The `&` operator (bitwise and) | |
2016 | BitAnd, | |
2017 | /// The `|` operator (bitwise or) | |
2018 | BitOr, | |
2019 | /// The `<<` operator (shift left) | |
2020 | Shl, | |
2021 | /// The `>>` operator (shift right) | |
2022 | Shr, | |
2023 | /// The `==` operator (equality) | |
2024 | Eq, | |
2025 | /// The `<` operator (less than) | |
2026 | Lt, | |
2027 | /// The `<=` operator (less than or equal to) | |
2028 | Le, | |
2029 | /// The `!=` operator (not equal to) | |
2030 | Ne, | |
2031 | /// The `>=` operator (greater than or equal to) | |
2032 | Ge, | |
2033 | /// The `>` operator (greater than) | |
2034 | Gt, | |
7cac9316 XL |
2035 | /// The `ptr.offset` operator |
2036 | Offset, | |
e9174d1e SL |
2037 | } |
2038 | ||
3157f602 XL |
2039 | impl BinOp { |
2040 | pub fn is_checkable(self) -> bool { | |
2041 | use self::BinOp::*; | |
2042 | match self { | |
2043 | Add | Sub | Mul | Shl | Shr => true, | |
94b46f34 | 2044 | _ => false, |
3157f602 XL |
2045 | } |
2046 | } | |
2047 | } | |
2048 | ||
3dfed10e | 2049 | #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] |
7cac9316 | 2050 | pub enum NullOp { |
9fa01778 | 2051 | /// Returns the size of a value of that type |
7cac9316 | 2052 | SizeOf, |
9fa01778 | 2053 | /// Creates a new uninitialized box for a value of that type |
7cac9316 XL |
2054 | Box, |
2055 | } | |
2056 | ||
3dfed10e | 2057 | #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] |
e9174d1e SL |
2058 | pub enum UnOp { |
2059 | /// The `!` operator for logical inversion | |
2060 | Not, | |
2061 | /// The `-` operator for negation | |
b039eaaf | 2062 | Neg, |
e9174d1e SL |
2063 | } |
2064 | ||
b039eaaf | 2065 | impl<'tcx> Debug for Rvalue<'tcx> { |
0bf4aa26 | 2066 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
2067 | use self::Rvalue::*; |
2068 | ||
2069 | match *self { | |
ff7c6d11 | 2070 | Use(ref place) => write!(fmt, "{:?}", place), |
ba9703b0 XL |
2071 | Repeat(ref a, ref b) => { |
2072 | write!(fmt, "[{:?}; ", a)?; | |
2073 | pretty_print_const(b, fmt, false)?; | |
2074 | write!(fmt, "]") | |
2075 | } | |
9cc50fc6 | 2076 | Len(ref a) => write!(fmt, "Len({:?})", a), |
ff7c6d11 XL |
2077 | Cast(ref kind, ref place, ref ty) => { |
2078 | write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind) | |
2079 | } | |
9cc50fc6 | 2080 | BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b), |
3157f602 XL |
2081 | CheckedBinaryOp(ref op, ref a, ref b) => { |
2082 | write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b) | |
2083 | } | |
e9174d1e | 2084 | UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), |
ff7c6d11 | 2085 | Discriminant(ref place) => write!(fmt, "discriminant({:?})", place), |
7cac9316 | 2086 | NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), |
f9f354fc XL |
2087 | ThreadLocalRef(did) => ty::tls::with(|tcx| { |
2088 | let muta = tcx.static_mutability(did).unwrap().prefix_str(); | |
2089 | write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did)) | |
2090 | }), | |
ff7c6d11 | 2091 | Ref(region, borrow_kind, ref place) => { |
9cc50fc6 SL |
2092 | let kind_str = match borrow_kind { |
2093 | BorrowKind::Shared => "", | |
0bf4aa26 | 2094 | BorrowKind::Shallow => "shallow ", |
2c00a5a8 | 2095 | BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", |
9cc50fc6 | 2096 | }; |
041b39d2 | 2097 | |
3b2f2976 | 2098 | // When printing regions, add trailing space if necessary. |
532ac7d7 XL |
2099 | let print_region = ty::tls::with(|tcx| { |
2100 | tcx.sess.verbose() || tcx.sess.opts.debugging_opts.identify_regions | |
2101 | }); | |
2102 | let region = if print_region { | |
8faf50e0 | 2103 | let mut region = region.to_string(); |
74b04a01 | 2104 | if !region.is_empty() { |
94b46f34 XL |
2105 | region.push(' '); |
2106 | } | |
041b39d2 XL |
2107 | region |
2108 | } else { | |
3b2f2976 | 2109 | // Do not even print 'static |
b7449926 | 2110 | String::new() |
041b39d2 | 2111 | }; |
ff7c6d11 | 2112 | write!(fmt, "&{}{}{:?}", region, kind_str, place) |
9cc50fc6 SL |
2113 | } |
2114 | ||
dfeec247 XL |
2115 | AddressOf(mutability, ref place) => { |
2116 | let kind_str = match mutability { | |
2117 | Mutability::Mut => "mut", | |
2118 | Mutability::Not => "const", | |
2119 | }; | |
2120 | ||
2121 | write!(fmt, "&raw {} {:?}", kind_str, place) | |
2122 | } | |
2123 | ||
ff7c6d11 | 2124 | Aggregate(ref kind, ref places) => { |
ba9703b0 XL |
2125 | let fmt_tuple = |fmt: &mut Formatter<'_>, name: &str| { |
2126 | let mut tuple_fmt = fmt.debug_tuple(name); | |
ff7c6d11 XL |
2127 | for place in places { |
2128 | tuple_fmt.field(place); | |
9cc50fc6 SL |
2129 | } |
2130 | tuple_fmt.finish() | |
ba9703b0 | 2131 | }; |
9cc50fc6 | 2132 | |
cc61c64b | 2133 | match **kind { |
ff7c6d11 | 2134 | AggregateKind::Array(_) => write!(fmt, "{:?}", places), |
9cc50fc6 | 2135 | |
ba9703b0 XL |
2136 | AggregateKind::Tuple => { |
2137 | if places.is_empty() { | |
2138 | write!(fmt, "()") | |
2139 | } else { | |
2140 | fmt_tuple(fmt, "") | |
2141 | } | |
2142 | } | |
9cc50fc6 | 2143 | |
b7449926 | 2144 | AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => { |
9cc50fc6 | 2145 | let variant_def = &adt_def.variants[variant]; |
54a0048b | 2146 | |
ba9703b0 XL |
2147 | let name = ty::tls::with(|tcx| { |
2148 | let mut name = String::new(); | |
532ac7d7 | 2149 | let substs = tcx.lift(&substs).expect("could not lift for printing"); |
ba9703b0 | 2150 | FmtPrinter::new(tcx, &mut name, Namespace::ValueNS) |
532ac7d7 | 2151 | .print_def_path(variant_def.def_id, substs)?; |
ba9703b0 | 2152 | Ok(name) |
532ac7d7 | 2153 | })?; |
9cc50fc6 | 2154 | |
c30ab7b3 | 2155 | match variant_def.ctor_kind { |
ba9703b0 XL |
2156 | CtorKind::Const => fmt.write_str(&name), |
2157 | CtorKind::Fn => fmt_tuple(fmt, &name), | |
c30ab7b3 | 2158 | CtorKind::Fictive => { |
ba9703b0 | 2159 | let mut struct_fmt = fmt.debug_struct(&name); |
ff7c6d11 | 2160 | for (field, place) in variant_def.fields.iter().zip(places) { |
94b46f34 | 2161 | struct_fmt.field(&field.ident.as_str(), place); |
9cc50fc6 SL |
2162 | } |
2163 | struct_fmt.finish() | |
2164 | } | |
2165 | } | |
2166 | } | |
2167 | ||
60c5eb7d | 2168 | AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| { |
f9f354fc | 2169 | if let Some(def_id) = def_id.as_local() { |
3dfed10e | 2170 | let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); |
041b39d2 | 2171 | let name = if tcx.sess.opts.debugging_opts.span_free_formats { |
60c5eb7d XL |
2172 | let substs = tcx.lift(&substs).unwrap(); |
2173 | format!( | |
2174 | "[closure@{}]", | |
f9f354fc | 2175 | tcx.def_path_str_with_substs(def_id.to_def_id(), substs), |
60c5eb7d | 2176 | ) |
041b39d2 | 2177 | } else { |
f035d41b XL |
2178 | let span = tcx.hir().span(hir_id); |
2179 | format!("[closure@{}]", tcx.sess.source_map().span_to_string(span)) | |
041b39d2 | 2180 | }; |
9cc50fc6 SL |
2181 | let mut struct_fmt = fmt.debug_struct(&name); |
2182 | ||
f9f354fc | 2183 | if let Some(upvars) = tcx.upvars_mentioned(def_id) { |
dc9dc135 XL |
2184 | for (&var_id, place) in upvars.keys().zip(places) { |
2185 | let var_name = tcx.hir().name(var_id); | |
ff7c6d11 | 2186 | struct_fmt.field(&var_name.as_str(), place); |
9cc50fc6 | 2187 | } |
48663c56 | 2188 | } |
9cc50fc6 SL |
2189 | |
2190 | struct_fmt.finish() | |
2191 | } else { | |
2192 | write!(fmt, "[closure]") | |
2193 | } | |
2194 | }), | |
ea8adc8c XL |
2195 | |
2196 | AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| { | |
f9f354fc | 2197 | if let Some(def_id) = def_id.as_local() { |
3dfed10e | 2198 | let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); |
416331ca | 2199 | let name = format!("[generator@{:?}]", tcx.hir().span(hir_id)); |
ea8adc8c XL |
2200 | let mut struct_fmt = fmt.debug_struct(&name); |
2201 | ||
f9f354fc | 2202 | if let Some(upvars) = tcx.upvars_mentioned(def_id) { |
dc9dc135 XL |
2203 | for (&var_id, place) in upvars.keys().zip(places) { |
2204 | let var_name = tcx.hir().name(var_id); | |
ff7c6d11 | 2205 | struct_fmt.field(&var_name.as_str(), place); |
ea8adc8c | 2206 | } |
48663c56 | 2207 | } |
ea8adc8c XL |
2208 | |
2209 | struct_fmt.finish() | |
2210 | } else { | |
2211 | write!(fmt, "[generator]") | |
2212 | } | |
2213 | }), | |
9cc50fc6 SL |
2214 | } |
2215 | } | |
e9174d1e SL |
2216 | } |
2217 | } | |
2218 | } | |
2219 | ||
2220 | /////////////////////////////////////////////////////////////////////////// | |
7453a54e SL |
2221 | /// Constants |
2222 | /// | |
2223 | /// Two constants are equal if they are the same constant. Note that | |
2224 | /// this does not necessarily mean that they are "==" in Rust -- in | |
2225 | /// particular one must be wary of `NaN`! | |
e9174d1e | 2226 | |
3dfed10e | 2227 | #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)] |
b039eaaf SL |
2228 | pub struct Constant<'tcx> { |
2229 | pub span: Span, | |
b7449926 XL |
2230 | |
2231 | /// Optional user-given type: for something like | |
2232 | /// `collect::<Vec<_>>`, this would be present and would | |
2233 | /// indicate that `Vec<_>` was explicitly specified. | |
2234 | /// | |
2235 | /// Needed for NLL to impose user-given type constraints. | |
0731742a | 2236 | pub user_ty: Option<UserTypeAnnotationIndex>, |
b7449926 | 2237 | |
532ac7d7 | 2238 | pub literal: &'tcx ty::Const<'tcx>, |
0bf4aa26 XL |
2239 | } |
2240 | ||
60c5eb7d XL |
2241 | impl Constant<'tcx> { |
2242 | pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> { | |
2243 | match self.literal.val.try_to_scalar() { | |
f9f354fc XL |
2244 | Some(Scalar::Ptr(ptr)) => match tcx.global_alloc(ptr.alloc_id) { |
2245 | GlobalAlloc::Static(def_id) => { | |
2246 | assert!(!tcx.is_thread_local_static(def_id)); | |
2247 | Some(def_id) | |
dfeec247 | 2248 | } |
f9f354fc | 2249 | _ => None, |
60c5eb7d XL |
2250 | }, |
2251 | _ => None, | |
2252 | } | |
2253 | } | |
2254 | } | |
2255 | ||
0bf4aa26 XL |
2256 | /// A collection of projections into user types. |
2257 | /// | |
2258 | /// They are projections because a binding can occur a part of a | |
2259 | /// parent pattern that has been ascribed a type. | |
2260 | /// | |
2261 | /// Its a collection because there can be multiple type ascriptions on | |
2262 | /// the path from the root of the pattern down to the binding itself. | |
2263 | /// | |
2264 | /// An example: | |
2265 | /// | |
2266 | /// ```rust | |
2267 | /// struct S<'a>((i32, &'a str), String); | |
2268 | /// let S((_, w): (i32, &'static str), _): S = ...; | |
2269 | /// // ------ ^^^^^^^^^^^^^^^^^^^ (1) | |
2270 | /// // --------------------------------- ^ (2) | |
2271 | /// ``` | |
2272 | /// | |
2273 | /// The highlights labelled `(1)` show the subpattern `(_, w)` being | |
2274 | /// ascribed the type `(i32, &'static str)`. | |
2275 | /// | |
2276 | /// The highlights labelled `(2)` show the whole pattern being | |
2277 | /// ascribed the type `S`. | |
2278 | /// | |
2279 | /// In this example, when we descend to `w`, we will have built up the | |
2280 | /// following two projected types: | |
2281 | /// | |
2282 | /// * base: `S`, projection: `(base.0).1` | |
2283 | /// * base: `(i32, &'static str)`, projection: `base.1` | |
2284 | /// | |
2285 | /// The first will lead to the constraint `w: &'1 str` (for some | |
2286 | /// inferred region `'1`). The second will lead to the constraint `w: | |
2287 | /// &'static str`. | |
3dfed10e | 2288 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
532ac7d7 | 2289 | pub struct UserTypeProjections { |
f9f354fc | 2290 | pub contents: Vec<(UserTypeProjection, Span)>, |
0bf4aa26 XL |
2291 | } |
2292 | ||
532ac7d7 | 2293 | impl<'tcx> UserTypeProjections { |
0bf4aa26 XL |
2294 | pub fn none() -> Self { |
2295 | UserTypeProjections { contents: vec![] } | |
2296 | } | |
2297 | ||
f9f354fc XL |
2298 | pub fn is_empty(&self) -> bool { |
2299 | self.contents.is_empty() | |
2300 | } | |
2301 | ||
416331ca | 2302 | pub fn from_projections(projs: impl Iterator<Item = (UserTypeProjection, Span)>) -> Self { |
0bf4aa26 XL |
2303 | UserTypeProjections { contents: projs.collect() } |
2304 | } | |
2305 | ||
dfeec247 XL |
2306 | pub fn projections_and_spans( |
2307 | &self, | |
2308 | ) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator { | |
0bf4aa26 XL |
2309 | self.contents.iter() |
2310 | } | |
2311 | ||
dfeec247 | 2312 | pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator { |
0bf4aa26 XL |
2313 | self.contents.iter().map(|&(ref user_type, _span)| user_type) |
2314 | } | |
0731742a | 2315 | |
416331ca | 2316 | pub fn push_projection(mut self, user_ty: &UserTypeProjection, span: Span) -> Self { |
0731742a XL |
2317 | self.contents.push((user_ty.clone(), span)); |
2318 | self | |
2319 | } | |
2320 | ||
2321 | fn map_projections( | |
2322 | mut self, | |
416331ca | 2323 | mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection, |
0731742a XL |
2324 | ) -> Self { |
2325 | self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect(); | |
2326 | self | |
2327 | } | |
2328 | ||
2329 | pub fn index(self) -> Self { | |
2330 | self.map_projections(|pat_ty_proj| pat_ty_proj.index()) | |
2331 | } | |
2332 | ||
2333 | pub fn subslice(self, from: u32, to: u32) -> Self { | |
2334 | self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) | |
2335 | } | |
2336 | ||
2337 | pub fn deref(self) -> Self { | |
2338 | self.map_projections(|pat_ty_proj| pat_ty_proj.deref()) | |
2339 | } | |
2340 | ||
2341 | pub fn leaf(self, field: Field) -> Self { | |
2342 | self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field)) | |
2343 | } | |
2344 | ||
416331ca | 2345 | pub fn variant(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx, field: Field) -> Self { |
0731742a XL |
2346 | self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field)) |
2347 | } | |
0bf4aa26 XL |
2348 | } |
2349 | ||
2350 | /// Encodes the effect of a user-supplied type annotation on the | |
2351 | /// subcomponents of a pattern. The effect is determined by applying the | |
2352 | /// given list of proejctions to some underlying base type. Often, | |
2353 | /// the projection element list `projs` is empty, in which case this | |
2354 | /// directly encodes a type in `base`. But in the case of complex patterns with | |
2355 | /// subpatterns and bindings, we want to apply only a *part* of the type to a variable, | |
2356 | /// in which case the `projs` vector is used. | |
2357 | /// | |
2358 | /// Examples: | |
2359 | /// | |
2360 | /// * `let x: T = ...` -- here, the `projs` vector is empty. | |
2361 | /// | |
2362 | /// * `let (x, _): T = ...` -- here, the `projs` vector would contain | |
2363 | /// `field[0]` (aka `.0`), indicating that the type of `s` is | |
2364 | /// determined by finding the type of the `.0` field from `T`. | |
3dfed10e | 2365 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq)] |
532ac7d7 | 2366 | pub struct UserTypeProjection { |
0731742a | 2367 | pub base: UserTypeAnnotationIndex, |
dc9dc135 | 2368 | pub projs: Vec<ProjectionKind>, |
0bf4aa26 XL |
2369 | } |
2370 | ||
416331ca | 2371 | impl Copy for ProjectionKind {} |
0bf4aa26 | 2372 | |
532ac7d7 | 2373 | impl UserTypeProjection { |
0731742a XL |
2374 | pub(crate) fn index(mut self) -> Self { |
2375 | self.projs.push(ProjectionElem::Index(())); | |
2376 | self | |
2377 | } | |
2378 | ||
2379 | pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self { | |
60c5eb7d | 2380 | self.projs.push(ProjectionElem::Subslice { from, to, from_end: true }); |
0731742a XL |
2381 | self |
2382 | } | |
2383 | ||
2384 | pub(crate) fn deref(mut self) -> Self { | |
2385 | self.projs.push(ProjectionElem::Deref); | |
2386 | self | |
2387 | } | |
2388 | ||
2389 | pub(crate) fn leaf(mut self, field: Field) -> Self { | |
2390 | self.projs.push(ProjectionElem::Field(field, ())); | |
2391 | self | |
2392 | } | |
2393 | ||
2394 | pub(crate) fn variant( | |
2395 | mut self, | |
ba9703b0 | 2396 | adt_def: &AdtDef, |
0731742a XL |
2397 | variant_index: VariantIdx, |
2398 | field: Field, | |
2399 | ) -> Self { | |
532ac7d7 XL |
2400 | self.projs.push(ProjectionElem::Downcast( |
2401 | Some(adt_def.variants[variant_index].ident.name), | |
416331ca XL |
2402 | variant_index, |
2403 | )); | |
0731742a XL |
2404 | self.projs.push(ProjectionElem::Field(field, ())); |
2405 | self | |
2406 | } | |
2407 | } | |
2408 | ||
532ac7d7 | 2409 | CloneTypeFoldableAndLiftImpls! { ProjectionKind, } |
0bf4aa26 | 2410 | |
532ac7d7 | 2411 | impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { |
dc9dc135 | 2412 | fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { |
9fa01778 | 2413 | use crate::mir::ProjectionElem::*; |
0bf4aa26 XL |
2414 | |
2415 | let base = self.base.fold_with(folder); | |
416331ca XL |
2416 | let projs: Vec<_> = self |
2417 | .projs | |
0bf4aa26 | 2418 | .iter() |
dfeec247 | 2419 | .map(|&elem| match elem { |
416331ca | 2420 | Deref => Deref, |
dfeec247 | 2421 | Field(f, ()) => Field(f, ()), |
416331ca | 2422 | Index(()) => Index(()), |
dfeec247 XL |
2423 | Downcast(symbol, variantidx) => Downcast(symbol, variantidx), |
2424 | ConstantIndex { offset, min_length, from_end } => { | |
2425 | ConstantIndex { offset, min_length, from_end } | |
2426 | } | |
2427 | Subslice { from, to, from_end } => Subslice { from, to, from_end }, | |
416331ca | 2428 | }) |
0bf4aa26 XL |
2429 | .collect(); |
2430 | ||
2431 | UserTypeProjection { base, projs } | |
2432 | } | |
2433 | ||
2434 | fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { | |
2435 | self.base.visit_with(visitor) | |
2436 | // Note: there's nothing in `self.proj` to visit. | |
2437 | } | |
2438 | } | |
2439 | ||
e74abb32 | 2440 | rustc_index::newtype_index! { |
b7449926 | 2441 | pub struct Promoted { |
532ac7d7 | 2442 | derive [HashStable] |
b7449926 XL |
2443 | DEBUG_FORMAT = "promoted[{}]" |
2444 | } | |
2445 | } | |
abe05a73 | 2446 | |
9cc50fc6 | 2447 | impl<'tcx> Debug for Constant<'tcx> { |
0bf4aa26 | 2448 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
dc9dc135 | 2449 | write!(fmt, "{}", self) |
9cc50fc6 SL |
2450 | } |
2451 | } | |
2452 | ||
dc9dc135 XL |
2453 | impl<'tcx> Display for Constant<'tcx> { |
2454 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { | |
3dfed10e XL |
2455 | match self.literal.ty.kind { |
2456 | ty::FnDef(..) => {} | |
2457 | _ => write!(fmt, "const ")?, | |
2458 | } | |
ba9703b0 | 2459 | pretty_print_const(self.literal, fmt, true) |
dc9dc135 | 2460 | } |
9cc50fc6 | 2461 | } |
3157f602 | 2462 | |
ba9703b0 XL |
2463 | fn pretty_print_const( |
2464 | c: &ty::Const<'tcx>, | |
2465 | fmt: &mut Formatter<'_>, | |
2466 | print_types: bool, | |
2467 | ) -> fmt::Result { | |
2468 | use crate::ty::print::PrettyPrinter; | |
2469 | ty::tls::with(|tcx| { | |
2470 | let literal = tcx.lift(&c).unwrap(); | |
2471 | let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS); | |
2472 | cx.print_alloc_ids = true; | |
2473 | cx.pretty_print_const(literal, print_types)?; | |
2474 | Ok(()) | |
2475 | }) | |
2476 | } | |
2477 | ||
dc9dc135 | 2478 | impl<'tcx> graph::DirectedGraph for Body<'tcx> { |
3157f602 | 2479 | type Node = BasicBlock; |
8faf50e0 | 2480 | } |
3157f602 | 2481 | |
dc9dc135 | 2482 | impl<'tcx> graph::WithNumNodes for Body<'tcx> { |
f9f354fc | 2483 | #[inline] |
94b46f34 XL |
2484 | fn num_nodes(&self) -> usize { |
2485 | self.basic_blocks.len() | |
2486 | } | |
8faf50e0 | 2487 | } |
3157f602 | 2488 | |
dc9dc135 | 2489 | impl<'tcx> graph::WithStartNode for Body<'tcx> { |
f9f354fc | 2490 | #[inline] |
94b46f34 XL |
2491 | fn start_node(&self) -> Self::Node { |
2492 | START_BLOCK | |
2493 | } | |
8faf50e0 | 2494 | } |
3157f602 | 2495 | |
dc9dc135 | 2496 | impl<'tcx> graph::WithSuccessors for Body<'tcx> { |
f9f354fc | 2497 | #[inline] |
dfeec247 | 2498 | fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter { |
83c7162d | 2499 | self.basic_blocks[node].terminator().successors().cloned() |
3157f602 XL |
2500 | } |
2501 | } | |
2502 | ||
dc9dc135 | 2503 | impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { |
3157f602 | 2504 | type Item = BasicBlock; |
83c7162d | 2505 | type Iter = iter::Cloned<Successors<'b>>; |
3157f602 | 2506 | } |
9e0c209e | 2507 | |
f9f354fc XL |
2508 | impl graph::GraphPredecessors<'graph> for Body<'tcx> { |
2509 | type Item = BasicBlock; | |
2510 | type Iter = smallvec::IntoIter<[BasicBlock; 4]>; | |
2511 | } | |
2512 | ||
2513 | impl graph::WithPredecessors for Body<'tcx> { | |
2514 | #[inline] | |
2515 | fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter { | |
2516 | self.predecessors()[node].clone().into_iter() | |
2517 | } | |
2518 | } | |
2519 | ||
ba9703b0 XL |
2520 | /// `Location` represents the position of the start of the statement; or, if |
2521 | /// `statement_index` equals the number of statements, then the start of the | |
2522 | /// terminator. | |
532ac7d7 | 2523 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)] |
9e0c209e | 2524 | pub struct Location { |
e1599b0c | 2525 | /// The block that the location is within. |
9e0c209e SL |
2526 | pub block: BasicBlock, |
2527 | ||
9e0c209e SL |
2528 | pub statement_index: usize, |
2529 | } | |
2530 | ||
2531 | impl fmt::Debug for Location { | |
0bf4aa26 | 2532 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
9e0c209e SL |
2533 | write!(fmt, "{:?}[{}]", self.block, self.statement_index) |
2534 | } | |
2535 | } | |
2536 | ||
2537 | impl Location { | |
416331ca | 2538 | pub const START: Location = Location { block: START_BLOCK, statement_index: 0 }; |
83c7162d | 2539 | |
abe05a73 XL |
2540 | /// Returns the location immediately after this one within the enclosing block. |
2541 | /// | |
2542 | /// Note that if this location represents a terminator, then the | |
2543 | /// resulting location would be out of bounds and invalid. | |
2544 | pub fn successor_within_block(&self) -> Location { | |
416331ca | 2545 | Location { block: self.block, statement_index: self.statement_index + 1 } |
abe05a73 XL |
2546 | } |
2547 | ||
a1dfa0c6 | 2548 | /// Returns `true` if `other` is earlier in the control flow graph than `self`. |
f9f354fc | 2549 | pub fn is_predecessor_of<'tcx>(&self, other: Location, body: &Body<'tcx>) -> bool { |
a1dfa0c6 XL |
2550 | // If we are in the same block as the other location and are an earlier statement |
2551 | // then we are a predecessor of `other`. | |
2552 | if self.block == other.block && self.statement_index < other.statement_index { | |
2553 | return true; | |
2554 | } | |
2555 | ||
f9f354fc XL |
2556 | let predecessors = body.predecessors(); |
2557 | ||
a1dfa0c6 | 2558 | // If we're in another block, then we want to check that block is a predecessor of `other`. |
f9f354fc | 2559 | let mut queue: Vec<BasicBlock> = predecessors[other.block].to_vec(); |
a1dfa0c6 XL |
2560 | let mut visited = FxHashSet::default(); |
2561 | ||
2562 | while let Some(block) = queue.pop() { | |
2563 | // If we haven't visited this block before, then make sure we visit it's predecessors. | |
2564 | if visited.insert(block) { | |
f9f354fc | 2565 | queue.extend(predecessors[block].iter().cloned()); |
a1dfa0c6 XL |
2566 | } else { |
2567 | continue; | |
2568 | } | |
2569 | ||
2570 | // If we found the block that `self` is in, then we are a predecessor of `other` (since | |
2571 | // we found that block by looking at the predecessors of `other`). | |
2572 | if self.block == block { | |
2573 | return true; | |
2574 | } | |
2575 | } | |
2576 | ||
2577 | false | |
2578 | } | |
2579 | ||
83c7162d | 2580 | pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool { |
9e0c209e SL |
2581 | if self.block == other.block { |
2582 | self.statement_index <= other.statement_index | |
2583 | } else { | |
2584 | dominators.is_dominated_by(other.block, self.block) | |
2585 | } | |
2586 | } | |
2587 | } |