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