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