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