]>
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}; |
923072b8 FG |
6 | use crate::mir::interpret::{ |
7 | AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar, | |
8 | }; | |
9fa01778 | 9 | use crate::mir::visit::MirVisitable; |
416331ca | 10 | use crate::ty::adjustment::PointerCast; |
3dfed10e | 11 | use crate::ty::codec::{TyDecoder, TyEncoder}; |
923072b8 | 12 | use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable, TypeVisitor}; |
416331ca | 13 | use crate::ty::print::{FmtPrinter, Printer}; |
04454e1e | 14 | use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; |
29967ef6 | 15 | use crate::ty::{self, List, Ty, TyCtxt}; |
6a06907d | 16 | use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; |
a2a8927a | 17 | |
923072b8 | 18 | use rustc_data_structures::captures::Captures; |
5e7ed085 | 19 | use rustc_errors::ErrorGuaranteed; |
dfeec247 | 20 | use rustc_hir::def::{CtorKind, Namespace}; |
04454e1e | 21 | use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; |
dfeec247 | 22 | use rustc_hir::{self, GeneratorKind}; |
cdc7bbd5 | 23 | use rustc_hir::{self as hir, HirId}; |
a2a8927a | 24 | use rustc_session::Session; |
6a06907d | 25 | use rustc_target::abi::{Size, VariantIdx}; |
e1599b0c | 26 | |
416331ca | 27 | use polonius_engine::Atom; |
3dfed10e | 28 | pub use rustc_ast::Mutability; |
a1dfa0c6 | 29 | use rustc_data_structures::fx::FxHashSet; |
f9f354fc | 30 | use rustc_data_structures::graph::dominators::{dominators, Dominators}; |
60c5eb7d | 31 | use rustc_data_structures::graph::{self, GraphSuccessors}; |
dfeec247 | 32 | use rustc_index::bit_set::BitMatrix; |
e74abb32 | 33 | use rustc_index::vec::{Idx, IndexVec}; |
dfeec247 XL |
34 | use rustc_serialize::{Decodable, Encodable}; |
35 | use rustc_span::symbol::Symbol; | |
36 | use rustc_span::{Span, DUMMY_SP}; | |
f9f354fc | 37 | use rustc_target::asm::InlineAsmRegOrRegClass; |
a2a8927a XL |
38 | |
39 | use either::Either; | |
40 | ||
94b46f34 | 41 | use std::borrow::Cow; |
6a06907d | 42 | use std::convert::TryInto; |
416331ca | 43 | use std::fmt::{self, Debug, Display, Formatter, Write}; |
29967ef6 | 44 | use std::ops::{ControlFlow, Index, IndexMut}; |
94b46f34 | 45 | use std::slice; |
ba9703b0 | 46 | use std::{iter, mem, option}; |
83c7162d | 47 | |
5869c6ff | 48 | use self::graph_cyclic_cache::GraphIsCyclicCache; |
f9f354fc | 49 | use self::predecessors::{PredecessorCache, Predecessors}; |
dfeec247 | 50 | pub use self::query::*; |
5e7ed085 | 51 | use self::switch_sources::{SwitchSourceCache, SwitchSources}; |
3157f602 | 52 | |
f035d41b | 53 | pub mod coverage; |
c295e0f8 XL |
54 | mod generic_graph; |
55 | pub mod generic_graphviz; | |
5869c6ff | 56 | mod graph_cyclic_cache; |
c295e0f8 | 57 | pub mod graphviz; |
ff7c6d11 XL |
58 | pub mod interpret; |
59 | pub mod mono; | |
c295e0f8 | 60 | pub mod patch; |
f9f354fc | 61 | mod predecessors; |
c295e0f8 | 62 | pub mod pretty; |
dfeec247 | 63 | mod query; |
c295e0f8 | 64 | pub mod spanview; |
5e7ed085 | 65 | mod switch_sources; |
94b46f34 | 66 | pub mod tcx; |
f035d41b | 67 | pub mod terminator; |
04454e1e | 68 | use crate::mir::traversal::PostorderCache; |
f035d41b | 69 | pub use terminator::*; |
04454e1e | 70 | |
94b46f34 | 71 | pub mod traversal; |
ba9703b0 | 72 | mod type_foldable; |
94b46f34 | 73 | pub mod visit; |
3157f602 | 74 | |
c295e0f8 XL |
75 | pub use self::generic_graph::graphviz_safe_def_name; |
76 | pub use self::graphviz::write_mir_graphviz; | |
77 | pub use self::pretty::{ | |
78 | create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere, | |
79 | }; | |
80 | ||
041b39d2 | 81 | /// Types for locals |
5869c6ff | 82 | pub type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>; |
041b39d2 XL |
83 | |
84 | pub trait HasLocalDecls<'tcx> { | |
85 | fn local_decls(&self) -> &LocalDecls<'tcx>; | |
86 | } | |
87 | ||
88 | impl<'tcx> HasLocalDecls<'tcx> for LocalDecls<'tcx> { | |
6a06907d | 89 | #[inline] |
041b39d2 XL |
90 | fn local_decls(&self) -> &LocalDecls<'tcx> { |
91 | self | |
92 | } | |
93 | } | |
94 | ||
dc9dc135 | 95 | impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { |
6a06907d | 96 | #[inline] |
041b39d2 XL |
97 | fn local_decls(&self) -> &LocalDecls<'tcx> { |
98 | &self.local_decls | |
99 | } | |
100 | } | |
101 | ||
c295e0f8 XL |
102 | /// A streamlined trait that you can implement to create a pass; the |
103 | /// pass will be named after the type, and it will consist of a main | |
104 | /// loop that goes over each available MIR and applies `run_pass`. | |
105 | pub trait MirPass<'tcx> { | |
106 | fn name(&self) -> Cow<'_, str> { | |
107 | let name = std::any::type_name::<Self>(); | |
108 | if let Some(tail) = name.rfind(':') { | |
109 | Cow::from(&name[tail + 1..]) | |
110 | } else { | |
111 | Cow::from(name) | |
112 | } | |
113 | } | |
114 | ||
a2a8927a XL |
115 | /// Returns `true` if this pass is enabled with the current combination of compiler flags. |
116 | fn is_enabled(&self, _sess: &Session) -> bool { | |
117 | true | |
118 | } | |
119 | ||
c295e0f8 | 120 | fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>); |
a2a8927a XL |
121 | |
122 | /// If this pass causes the MIR to enter a new phase, return that phase. | |
123 | fn phase_change(&self) -> Option<MirPhase> { | |
124 | None | |
125 | } | |
126 | ||
127 | fn is_mir_dump_enabled(&self) -> bool { | |
128 | true | |
129 | } | |
c295e0f8 XL |
130 | } |
131 | ||
a1dfa0c6 XL |
132 | /// The various "big phases" that MIR goes through. |
133 | /// | |
3dfed10e | 134 | /// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the |
04454e1e FG |
135 | /// dialects forbid certain variants or values in certain phases. The sections below summarize the |
136 | /// changes, but do not document them thoroughly. The full documentation is found in the appropriate | |
137 | /// documentation for the thing the change is affecting. | |
3dfed10e | 138 | /// |
e1599b0c | 139 | /// Warning: ordering of variants is significant. |
3dfed10e | 140 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] |
ba9703b0 | 141 | #[derive(HashStable)] |
a1dfa0c6 | 142 | pub enum MirPhase { |
04454e1e FG |
143 | /// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also |
144 | /// the MIR that analysis such as borrowck uses. | |
145 | /// | |
146 | /// One important thing to remember about the behavior of this section of MIR is that drop terminators | |
147 | /// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each | |
148 | /// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop | |
149 | /// flag. Of course, this means that it is important that the drop elaboration can accurately recognize | |
150 | /// when things are initialized and when things are de-initialized. That means any code running on this | |
151 | /// version of MIR must be sure to produce output that drop elaboration can reason about. See the | |
152 | /// section on the drop terminatorss for more details. | |
5e7ed085 | 153 | Built = 0, |
3dfed10e XL |
154 | // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query). |
155 | // We used to have this for pre-miri MIR based const eval. | |
a1dfa0c6 | 156 | Const = 1, |
3dfed10e XL |
157 | /// This phase checks the MIR for promotable elements and takes them out of the main MIR body |
158 | /// by creating a new MIR body per promoted element. After this phase (and thus the termination | |
159 | /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir` | |
160 | /// query. | |
5e7ed085 FG |
161 | ConstsPromoted = 2, |
162 | /// Beginning with this phase, the following variants are disallowed: | |
163 | /// * [`TerminatorKind::DropAndReplace`](terminator::TerminatorKind::DropAndReplace) | |
164 | /// * [`TerminatorKind::FalseUnwind`](terminator::TerminatorKind::FalseUnwind) | |
165 | /// * [`TerminatorKind::FalseEdge`](terminator::TerminatorKind::FalseEdge) | |
166 | /// * [`StatementKind::FakeRead`] | |
167 | /// * [`StatementKind::AscribeUserType`] | |
168 | /// * [`Rvalue::Ref`] with `BorrowKind::Shallow` | |
169 | /// | |
170 | /// And the following variant is allowed: | |
171 | /// * [`StatementKind::Retag`] | |
172 | /// | |
173 | /// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop` | |
04454e1e FG |
174 | /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands |
175 | /// are allowed for non-`Copy` types. | |
5e7ed085 | 176 | DropsLowered = 3, |
923072b8 FG |
177 | /// After this projections may only contain deref projections as the first element. |
178 | Derefered = 4, | |
5e7ed085 FG |
179 | /// Beginning with this phase, the following variant is disallowed: |
180 | /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array` | |
181 | /// | |
182 | /// And the following variant is allowed: | |
183 | /// * [`StatementKind::SetDiscriminant`] | |
923072b8 | 184 | Deaggregated = 5, |
04454e1e FG |
185 | /// Before this phase, generators are in the "source code" form, featuring `yield` statements |
186 | /// and such. With this phase change, they are transformed into a proper state machine. Running | |
187 | /// optimizations before this change can be potentially dangerous because the source code is to | |
188 | /// some extent a "lie." In particular, `yield` terminators effectively make the value of all | |
189 | /// locals visible to the caller. This means that dead store elimination before them, or code | |
190 | /// motion across them, is not correct in general. This is also exasperated by type checking | |
191 | /// having pre-computed a list of the types that it thinks are ok to be live across a yield | |
192 | /// point - this is necessary to decide eg whether autotraits are implemented. Introducing new | |
193 | /// types across a yield point will lead to ICEs becaues of this. | |
194 | /// | |
5e7ed085 FG |
195 | /// Beginning with this phase, the following variants are disallowed: |
196 | /// * [`TerminatorKind::Yield`](terminator::TerminatorKind::Yield) | |
923072b8 FG |
197 | /// * [`TerminatorKind::GeneratorDrop`](terminator::TerminatorKind::GeneratorDrop) |
198 | /// * [`ProjectionElem::Deref`] of `Box` | |
199 | GeneratorsLowered = 6, | |
200 | Optimized = 7, | |
a1dfa0c6 XL |
201 | } |
202 | ||
203 | impl MirPhase { | |
e1599b0c | 204 | /// Gets the index of the current MirPhase within the set of all `MirPhase`s. |
a1dfa0c6 XL |
205 | pub fn phase_index(&self) -> usize { |
206 | *self as usize | |
207 | } | |
208 | } | |
209 | ||
29967ef6 | 210 | /// Where a specific `mir::Body` comes from. |
5099ac24 | 211 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
29967ef6 XL |
212 | #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable)] |
213 | pub struct MirSource<'tcx> { | |
214 | pub instance: InstanceDef<'tcx>, | |
215 | ||
216 | /// If `Some`, this is a promoted rvalue within the parent function. | |
217 | pub promoted: Option<Promoted>, | |
218 | } | |
219 | ||
220 | impl<'tcx> MirSource<'tcx> { | |
221 | pub fn item(def_id: DefId) -> Self { | |
222 | MirSource { | |
223 | instance: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), | |
224 | promoted: None, | |
225 | } | |
226 | } | |
227 | ||
228 | pub fn from_instance(instance: InstanceDef<'tcx>) -> Self { | |
229 | MirSource { instance, promoted: None } | |
230 | } | |
231 | ||
232 | pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> { | |
233 | self.instance.with_opt_param() | |
234 | } | |
235 | ||
236 | #[inline] | |
237 | pub fn def_id(&self) -> DefId { | |
238 | self.instance.def_id() | |
239 | } | |
240 | } | |
241 | ||
6a06907d XL |
242 | #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)] |
243 | pub struct GeneratorInfo<'tcx> { | |
244 | /// The yield type of the function, if it is a generator. | |
245 | pub yield_ty: Option<Ty<'tcx>>, | |
246 | ||
247 | /// Generator drop glue. | |
248 | pub generator_drop: Option<Body<'tcx>>, | |
249 | ||
250 | /// The layout of a generator. Produced by the state transformation. | |
251 | pub generator_layout: Option<GeneratorLayout<'tcx>>, | |
252 | ||
253 | /// If this is a generator then record the type of source expression that caused this generator | |
254 | /// to be created. | |
255 | pub generator_kind: GeneratorKind, | |
256 | } | |
257 | ||
e1599b0c | 258 | /// The lowered representation of a single function. |
3dfed10e | 259 | #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)] |
dc9dc135 | 260 | pub struct Body<'tcx> { |
29967ef6 | 261 | /// A list of basic blocks. References to basic block use a newtyped index type [`BasicBlock`] |
92a42be0 | 262 | /// that indexes into this vector. |
3157f602 | 263 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, |
e9174d1e | 264 | |
a1dfa0c6 XL |
265 | /// Records how far through the "desugaring and optimization" process this particular |
266 | /// MIR has traversed. This is particularly useful when inlining, since in that context | |
267 | /// we instantiate the promoted constants and add them to our promoted vector -- but those | |
268 | /// promoted items have already been optimized, whereas ours have not. This field allows | |
269 | /// us to see the difference and forego optimization on the inlined promoted items. | |
270 | pub phase: MirPhase, | |
271 | ||
29967ef6 XL |
272 | pub source: MirSource<'tcx>, |
273 | ||
e1599b0c | 274 | /// A list of source scopes; these are referenced by statements |
94b46f34 | 275 | /// and used for debuginfo. Indexed by a `SourceScope`. |
29967ef6 | 276 | pub source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>, |
54a0048b | 277 | |
6a06907d | 278 | pub generator: Option<Box<GeneratorInfo<'tcx>>>, |
60c5eb7d | 279 | |
c30ab7b3 SL |
280 | /// Declarations of locals. |
281 | /// | |
282 | /// The first local is the return value pointer, followed by `arg_count` | |
283 | /// locals for the function arguments, followed by any user-declared | |
284 | /// variables and temporaries. | |
041b39d2 | 285 | pub local_decls: LocalDecls<'tcx>, |
92a42be0 | 286 | |
e1599b0c | 287 | /// User type annotations. |
29967ef6 | 288 | pub user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, |
0731742a | 289 | |
e1599b0c | 290 | /// The number of arguments this function takes. |
c30ab7b3 SL |
291 | /// |
292 | /// Starting at local 1, `arg_count` locals will be provided by the caller | |
293 | /// and can be assumed to be initialized. | |
294 | /// | |
295 | /// If this MIR was built for a constant, this will be 0. | |
296 | pub arg_count: usize, | |
7453a54e | 297 | |
c30ab7b3 SL |
298 | /// Mark an argument local (which must be a tuple) as getting passed as |
299 | /// its individual components at the LLVM level. | |
300 | /// | |
301 | /// This is used for the "rust-call" ABI. | |
302 | pub spread_arg: Option<Local>, | |
303 | ||
60c5eb7d XL |
304 | /// Debug information pertaining to user variables, including captures. |
305 | pub var_debug_info: Vec<VarDebugInfo<'tcx>>, | |
48663c56 | 306 | |
e1599b0c | 307 | /// A span representing this MIR, for error reporting. |
7453a54e | 308 | pub span: Span, |
dfeec247 | 309 | |
f9f354fc XL |
310 | /// Constants that are required to evaluate successfully for this MIR to be well-formed. |
311 | /// We hold in this field all the constants we are not able to evaluate yet. | |
312 | pub required_consts: Vec<Constant<'tcx>>, | |
313 | ||
1b1a35ee XL |
314 | /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check. |
315 | /// | |
316 | /// Note that this does not actually mean that this body is not computable right now. | |
317 | /// The repeat count in the following example is polymorphic, but can still be evaluated | |
318 | /// without knowing anything about the type parameter `T`. | |
319 | /// | |
320 | /// ```rust | |
321 | /// fn test<T>() { | |
322 | /// let _ = [0; std::mem::size_of::<*mut T>()]; | |
323 | /// } | |
324 | /// ``` | |
325 | /// | |
326 | /// **WARNING**: Do not change this flags after the MIR was originally created, even if an optimization | |
327 | /// removed the last mention of all generic params. We do not want to rely on optimizations and | |
328 | /// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this. | |
329 | pub is_polymorphic: bool, | |
330 | ||
f9f354fc | 331 | predecessor_cache: PredecessorCache, |
5e7ed085 | 332 | switch_source_cache: SwitchSourceCache, |
5869c6ff | 333 | is_cyclic: GraphIsCyclicCache, |
04454e1e | 334 | postorder_cache: PostorderCache, |
5099ac24 | 335 | |
5e7ed085 | 336 | pub tainted_by_errors: Option<ErrorGuaranteed>, |
e9174d1e SL |
337 | } |
338 | ||
dc9dc135 | 339 | impl<'tcx> Body<'tcx> { |
94b46f34 | 340 | pub fn new( |
29967ef6 | 341 | source: MirSource<'tcx>, |
94b46f34 | 342 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, |
29967ef6 | 343 | source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>, |
0731742a | 344 | local_decls: LocalDecls<'tcx>, |
29967ef6 | 345 | user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, |
94b46f34 | 346 | arg_count: usize, |
60c5eb7d | 347 | var_debug_info: Vec<VarDebugInfo<'tcx>>, |
94b46f34 | 348 | span: Span, |
dfeec247 | 349 | generator_kind: Option<GeneratorKind>, |
5e7ed085 | 350 | tainted_by_errors: Option<ErrorGuaranteed>, |
94b46f34 | 351 | ) -> Self { |
e1599b0c | 352 | // We need `arg_count` locals, and one for the return place. |
94b46f34 | 353 | assert!( |
74b04a01 | 354 | local_decls.len() > arg_count, |
94b46f34 XL |
355 | "expected at least {} locals, got {}", |
356 | arg_count + 1, | |
357 | local_decls.len() | |
358 | ); | |
c30ab7b3 | 359 | |
1b1a35ee | 360 | let mut body = Body { |
5e7ed085 | 361 | phase: MirPhase::Built, |
29967ef6 | 362 | source, |
041b39d2 | 363 | basic_blocks, |
94b46f34 | 364 | source_scopes, |
6a06907d XL |
365 | generator: generator_kind.map(|generator_kind| { |
366 | Box::new(GeneratorInfo { | |
367 | yield_ty: None, | |
368 | generator_drop: None, | |
369 | generator_layout: None, | |
370 | generator_kind, | |
371 | }) | |
372 | }), | |
041b39d2 | 373 | local_decls, |
0731742a | 374 | user_type_annotations, |
041b39d2 | 375 | arg_count, |
c30ab7b3 | 376 | spread_arg: None, |
60c5eb7d | 377 | var_debug_info, |
041b39d2 | 378 | span, |
f9f354fc | 379 | required_consts: Vec::new(), |
1b1a35ee | 380 | is_polymorphic: false, |
f9f354fc | 381 | predecessor_cache: PredecessorCache::new(), |
5e7ed085 | 382 | switch_source_cache: SwitchSourceCache::new(), |
5869c6ff | 383 | is_cyclic: GraphIsCyclicCache::new(), |
04454e1e | 384 | postorder_cache: PostorderCache::new(), |
5099ac24 | 385 | tainted_by_errors, |
1b1a35ee | 386 | }; |
5099ac24 | 387 | body.is_polymorphic = body.has_param_types_or_consts(); |
1b1a35ee | 388 | body |
3157f602 XL |
389 | } |
390 | ||
dfeec247 XL |
391 | /// Returns a partially initialized MIR body containing only a list of basic blocks. |
392 | /// | |
393 | /// The returned MIR contains no `LocalDecl`s (even for the return place) or source scopes. It | |
394 | /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different | |
395 | /// crate. | |
396 | pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self { | |
5099ac24 | 397 | let mut body = Body { |
5e7ed085 | 398 | phase: MirPhase::Built, |
04454e1e | 399 | source: MirSource::item(CRATE_DEF_ID.to_def_id()), |
dfeec247 XL |
400 | basic_blocks, |
401 | source_scopes: IndexVec::new(), | |
6a06907d | 402 | generator: None, |
dfeec247 XL |
403 | local_decls: IndexVec::new(), |
404 | user_type_annotations: IndexVec::new(), | |
405 | arg_count: 0, | |
406 | spread_arg: None, | |
407 | span: DUMMY_SP, | |
f9f354fc | 408 | required_consts: Vec::new(), |
dfeec247 | 409 | var_debug_info: Vec::new(), |
1b1a35ee | 410 | is_polymorphic: false, |
f9f354fc | 411 | predecessor_cache: PredecessorCache::new(), |
5e7ed085 | 412 | switch_source_cache: SwitchSourceCache::new(), |
5869c6ff | 413 | is_cyclic: GraphIsCyclicCache::new(), |
04454e1e | 414 | postorder_cache: PostorderCache::new(), |
5099ac24 FG |
415 | tainted_by_errors: None, |
416 | }; | |
417 | body.is_polymorphic = body.has_param_types_or_consts(); | |
418 | body | |
dfeec247 XL |
419 | } |
420 | ||
3157f602 XL |
421 | #[inline] |
422 | pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> { | |
423 | &self.basic_blocks | |
424 | } | |
425 | ||
f9f354fc XL |
426 | #[inline] |
427 | pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { | |
428 | // Because the user could mutate basic block terminators via this reference, we need to | |
5869c6ff | 429 | // invalidate the caches. |
f9f354fc XL |
430 | // |
431 | // FIXME: Use a finer-grained API for this, so only transformations that alter terminators | |
5869c6ff | 432 | // invalidate the caches. |
f9f354fc | 433 | self.predecessor_cache.invalidate(); |
5e7ed085 | 434 | self.switch_source_cache.invalidate(); |
5869c6ff | 435 | self.is_cyclic.invalidate(); |
04454e1e | 436 | self.postorder_cache.invalidate(); |
f9f354fc XL |
437 | &mut self.basic_blocks |
438 | } | |
439 | ||
440 | #[inline] | |
441 | pub fn basic_blocks_and_local_decls_mut( | |
442 | &mut self, | |
443 | ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) { | |
444 | self.predecessor_cache.invalidate(); | |
5e7ed085 | 445 | self.switch_source_cache.invalidate(); |
5869c6ff | 446 | self.is_cyclic.invalidate(); |
04454e1e | 447 | self.postorder_cache.invalidate(); |
f9f354fc XL |
448 | (&mut self.basic_blocks, &mut self.local_decls) |
449 | } | |
450 | ||
f035d41b XL |
451 | #[inline] |
452 | pub fn basic_blocks_local_decls_mut_and_var_debug_info( | |
453 | &mut self, | |
454 | ) -> ( | |
455 | &mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, | |
456 | &mut LocalDecls<'tcx>, | |
457 | &mut Vec<VarDebugInfo<'tcx>>, | |
458 | ) { | |
459 | self.predecessor_cache.invalidate(); | |
5e7ed085 | 460 | self.switch_source_cache.invalidate(); |
5869c6ff | 461 | self.is_cyclic.invalidate(); |
04454e1e | 462 | self.postorder_cache.invalidate(); |
f035d41b XL |
463 | (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info) |
464 | } | |
465 | ||
e74abb32 XL |
466 | /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the |
467 | /// `START_BLOCK`. | |
468 | pub fn is_cfg_cyclic(&self) -> bool { | |
5869c6ff | 469 | self.is_cyclic.is_cyclic(self) |
e74abb32 XL |
470 | } |
471 | ||
c30ab7b3 SL |
472 | #[inline] |
473 | pub fn local_kind(&self, local: Local) -> LocalKind { | |
b7449926 | 474 | let index = local.as_usize(); |
c30ab7b3 | 475 | if index == 0 { |
94b46f34 XL |
476 | debug_assert!( |
477 | self.local_decls[local].mutability == Mutability::Mut, | |
478 | "return place should be mutable" | |
479 | ); | |
c30ab7b3 SL |
480 | |
481 | LocalKind::ReturnPointer | |
482 | } else if index < self.arg_count + 1 { | |
483 | LocalKind::Arg | |
60c5eb7d | 484 | } else if self.local_decls[local].is_user_variable() { |
c30ab7b3 SL |
485 | LocalKind::Var |
486 | } else { | |
c30ab7b3 SL |
487 | LocalKind::Temp |
488 | } | |
489 | } | |
490 | ||
a1dfa0c6 XL |
491 | /// Returns an iterator over all user-declared mutable locals. |
492 | #[inline] | |
923072b8 | 493 | pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + Captures<'tcx> + 'a { |
a1dfa0c6 XL |
494 | (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { |
495 | let local = Local::new(index); | |
496 | let decl = &self.local_decls[local]; | |
60c5eb7d | 497 | if decl.is_user_variable() && decl.mutability == Mutability::Mut { |
a1dfa0c6 XL |
498 | Some(local) |
499 | } else { | |
500 | None | |
501 | } | |
502 | }) | |
503 | } | |
504 | ||
83c7162d XL |
505 | /// Returns an iterator over all user-declared mutable arguments and locals. |
506 | #[inline] | |
923072b8 FG |
507 | pub fn mut_vars_and_args_iter<'a>( |
508 | &'a self, | |
509 | ) -> impl Iterator<Item = Local> + Captures<'tcx> + 'a { | |
83c7162d XL |
510 | (1..self.local_decls.len()).filter_map(move |index| { |
511 | let local = Local::new(index); | |
512 | let decl = &self.local_decls[local]; | |
60c5eb7d | 513 | if (decl.is_user_variable() || index < self.arg_count + 1) |
94b46f34 | 514 | && decl.mutability == Mutability::Mut |
83c7162d XL |
515 | { |
516 | Some(local) | |
517 | } else { | |
518 | None | |
519 | } | |
520 | }) | |
521 | } | |
522 | ||
c30ab7b3 SL |
523 | /// Returns an iterator over all function arguments. |
524 | #[inline] | |
60c5eb7d | 525 | pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator { |
94222f64 | 526 | (1..self.arg_count + 1).map(Local::new) |
e9174d1e | 527 | } |
9e0c209e | 528 | |
c30ab7b3 | 529 | /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all |
ff7c6d11 | 530 | /// locals that are neither arguments nor the return place). |
c30ab7b3 | 531 | #[inline] |
fc512014 XL |
532 | pub fn vars_and_temps_iter( |
533 | &self, | |
534 | ) -> impl DoubleEndedIterator<Item = Local> + ExactSizeIterator { | |
94222f64 XL |
535 | (self.arg_count + 1..self.local_decls.len()).map(Local::new) |
536 | } | |
537 | ||
538 | #[inline] | |
539 | pub fn drain_vars_and_temps<'a>(&'a mut self) -> impl Iterator<Item = LocalDecl<'tcx>> + 'a { | |
540 | self.local_decls.drain(self.arg_count + 1..) | |
9e0c209e SL |
541 | } |
542 | ||
543 | /// Changes a statement to a nop. This is both faster than deleting instructions and avoids | |
544 | /// invalidating statement indices in `Location`s. | |
545 | pub fn make_statement_nop(&mut self, location: Location) { | |
60c5eb7d | 546 | let block = &mut self.basic_blocks[location.block]; |
9e0c209e SL |
547 | debug_assert!(location.statement_index < block.statements.len()); |
548 | block.statements[location.statement_index].make_nop() | |
549 | } | |
ea8adc8c XL |
550 | |
551 | /// Returns the source info associated with `location`. | |
552 | pub fn source_info(&self, location: Location) -> &SourceInfo { | |
553 | let block = &self[location.block]; | |
554 | let stmts = &block.statements; | |
555 | let idx = location.statement_index; | |
abe05a73 | 556 | if idx < stmts.len() { |
ea8adc8c XL |
557 | &stmts[idx].source_info |
558 | } else { | |
0bf4aa26 | 559 | assert_eq!(idx, stmts.len()); |
ea8adc8c XL |
560 | &block.terminator().source_info |
561 | } | |
562 | } | |
abe05a73 | 563 | |
e1599b0c | 564 | /// Returns the return type; it always return first element from `local_decls` array. |
f9f354fc | 565 | #[inline] |
abe05a73 | 566 | pub fn return_ty(&self) -> Ty<'tcx> { |
ff7c6d11 | 567 | self.local_decls[RETURN_PLACE].ty |
abe05a73 | 568 | } |
b7449926 | 569 | |
e1599b0c | 570 | /// Gets the location of the terminator for the given block. |
f9f354fc | 571 | #[inline] |
b7449926 | 572 | pub fn terminator_loc(&self, bb: BasicBlock) -> Location { |
416331ca | 573 | Location { block: bb, statement_index: self[bb].statements.len() } |
b7449926 | 574 | } |
f9f354fc | 575 | |
a2a8927a XL |
576 | pub fn stmt_at(&self, location: Location) -> Either<&Statement<'tcx>, &Terminator<'tcx>> { |
577 | let Location { block, statement_index } = location; | |
578 | let block_data = &self.basic_blocks[block]; | |
579 | block_data | |
580 | .statements | |
581 | .get(statement_index) | |
582 | .map(Either::Left) | |
583 | .unwrap_or_else(|| Either::Right(block_data.terminator())) | |
584 | } | |
585 | ||
f9f354fc | 586 | #[inline] |
17df50a5 | 587 | pub fn predecessors(&self) -> &Predecessors { |
f9f354fc XL |
588 | self.predecessor_cache.compute(&self.basic_blocks) |
589 | } | |
590 | ||
04454e1e FG |
591 | /// `body.switch_sources()[&(target, switch)]` returns a list of switch |
592 | /// values that lead to a `target` block from a `switch` block. | |
5e7ed085 FG |
593 | #[inline] |
594 | pub fn switch_sources(&self) -> &SwitchSources { | |
595 | self.switch_source_cache.compute(&self.basic_blocks) | |
596 | } | |
597 | ||
f9f354fc XL |
598 | #[inline] |
599 | pub fn dominators(&self) -> Dominators<BasicBlock> { | |
600 | dominators(self) | |
601 | } | |
6a06907d XL |
602 | |
603 | #[inline] | |
604 | pub fn yield_ty(&self) -> Option<Ty<'tcx>> { | |
605 | self.generator.as_ref().and_then(|generator| generator.yield_ty) | |
606 | } | |
607 | ||
608 | #[inline] | |
609 | pub fn generator_layout(&self) -> Option<&GeneratorLayout<'tcx>> { | |
610 | self.generator.as_ref().and_then(|generator| generator.generator_layout.as_ref()) | |
611 | } | |
612 | ||
613 | #[inline] | |
614 | pub fn generator_drop(&self) -> Option<&Body<'tcx>> { | |
615 | self.generator.as_ref().and_then(|generator| generator.generator_drop.as_ref()) | |
616 | } | |
617 | ||
618 | #[inline] | |
619 | pub fn generator_kind(&self) -> Option<GeneratorKind> { | |
620 | self.generator.as_ref().map(|generator| generator.generator_kind) | |
621 | } | |
ea8adc8c XL |
622 | } |
623 | ||
3dfed10e | 624 | #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)] |
ea8adc8c XL |
625 | pub enum Safety { |
626 | Safe, | |
136023e0 | 627 | /// Unsafe because of compiler-generated unsafe code, like `await` desugaring |
ea8adc8c XL |
628 | BuiltinUnsafe, |
629 | /// Unsafe because of an unsafe fn | |
630 | FnUnsafe, | |
631 | /// Unsafe because of an `unsafe` block | |
532ac7d7 | 632 | ExplicitUnsafe(hir::HirId), |
e9174d1e SL |
633 | } |
634 | ||
dc9dc135 | 635 | impl<'tcx> Index<BasicBlock> for Body<'tcx> { |
9cc50fc6 SL |
636 | type Output = BasicBlockData<'tcx>; |
637 | ||
638 | #[inline] | |
639 | fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { | |
3157f602 | 640 | &self.basic_blocks()[index] |
9cc50fc6 SL |
641 | } |
642 | } | |
643 | ||
f9f354fc XL |
644 | impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> { |
645 | #[inline] | |
646 | fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { | |
647 | &mut self.basic_blocks_mut()[index] | |
648 | } | |
649 | } | |
650 | ||
60c5eb7d | 651 | #[derive(Copy, Clone, Debug, HashStable, TypeFoldable)] |
ff7c6d11 | 652 | pub enum ClearCrossCrate<T> { |
ea8adc8c | 653 | Clear, |
94b46f34 | 654 | Set(T), |
ea8adc8c XL |
655 | } |
656 | ||
8faf50e0 | 657 | impl<T> ClearCrossCrate<T> { |
ba9703b0 | 658 | pub fn as_ref(&self) -> ClearCrossCrate<&T> { |
60c5eb7d XL |
659 | match self { |
660 | ClearCrossCrate::Clear => ClearCrossCrate::Clear, | |
661 | ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v), | |
662 | } | |
663 | } | |
664 | ||
8faf50e0 XL |
665 | pub fn assert_crate_local(self) -> T { |
666 | match self { | |
667 | ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), | |
668 | ClearCrossCrate::Set(v) => v, | |
669 | } | |
670 | } | |
671 | } | |
672 | ||
f035d41b XL |
673 | const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; |
674 | const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; | |
675 | ||
923072b8 | 676 | impl<E: TyEncoder, T: Encodable<E>> Encodable<E> for ClearCrossCrate<T> { |
f035d41b | 677 | #[inline] |
923072b8 | 678 | fn encode(&self, e: &mut E) { |
3dfed10e | 679 | if E::CLEAR_CROSS_CRATE { |
923072b8 | 680 | return; |
3dfed10e XL |
681 | } |
682 | ||
f035d41b XL |
683 | match *self { |
684 | ClearCrossCrate::Clear => TAG_CLEAR_CROSS_CRATE_CLEAR.encode(e), | |
685 | ClearCrossCrate::Set(ref val) => { | |
923072b8 FG |
686 | TAG_CLEAR_CROSS_CRATE_SET.encode(e); |
687 | val.encode(e); | |
f035d41b XL |
688 | } |
689 | } | |
690 | } | |
691 | } | |
923072b8 | 692 | impl<D: TyDecoder, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> { |
f035d41b | 693 | #[inline] |
5099ac24 | 694 | fn decode(d: &mut D) -> ClearCrossCrate<T> { |
3dfed10e | 695 | if D::CLEAR_CROSS_CRATE { |
5099ac24 | 696 | return ClearCrossCrate::Clear; |
3dfed10e XL |
697 | } |
698 | ||
5099ac24 | 699 | let discr = u8::decode(d); |
f035d41b XL |
700 | |
701 | match discr { | |
5099ac24 | 702 | TAG_CLEAR_CROSS_CRATE_CLEAR => ClearCrossCrate::Clear, |
f035d41b | 703 | TAG_CLEAR_CROSS_CRATE_SET => { |
5099ac24 FG |
704 | let val = T::decode(d); |
705 | ClearCrossCrate::Set(val) | |
f035d41b | 706 | } |
5099ac24 | 707 | tag => panic!("Invalid tag for ClearCrossCrate: {:?}", tag), |
f035d41b XL |
708 | } |
709 | } | |
710 | } | |
ea8adc8c | 711 | |
3157f602 XL |
712 | /// Grouped information about the source code origin of a MIR entity. |
713 | /// Intended to be inspected by diagnostics and debuginfo. | |
714 | /// Most passes can work with it as a whole, within a single function. | |
60c5eb7d | 715 | // The unofficial Cranelift backend, at least as of #65828, needs `SourceInfo` to implement `Eq` and |
e74abb32 | 716 | // `Hash`. Please ping @bjorn3 if removing them. |
3dfed10e | 717 | #[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] |
3157f602 | 718 | pub struct SourceInfo { |
e1599b0c | 719 | /// The source span for the AST pertaining to this MIR entity. |
3157f602 XL |
720 | pub span: Span, |
721 | ||
94b46f34 XL |
722 | /// The source scope, keeping track of which bindings can be |
723 | /// seen by debuginfo, active lint levels, `unsafe {...}`, etc. | |
724 | pub scope: SourceScope, | |
3157f602 XL |
725 | } |
726 | ||
f9f354fc XL |
727 | impl SourceInfo { |
728 | #[inline] | |
729 | pub fn outermost(span: Span) -> Self { | |
730 | SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE } | |
731 | } | |
732 | } | |
733 | ||
e9174d1e | 734 | /////////////////////////////////////////////////////////////////////////// |
dfeec247 | 735 | // Borrow kinds |
94b46f34 | 736 | |
3dfed10e | 737 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] |
6a06907d | 738 | #[derive(Hash, HashStable)] |
e9174d1e SL |
739 | pub enum BorrowKind { |
740 | /// Data must be immutable and is aliasable. | |
741 | Shared, | |
742 | ||
0bf4aa26 XL |
743 | /// The immediately borrowed place must be immutable, but projections from |
744 | /// it don't need to be. For example, a shallow borrow of `a.b` doesn't | |
745 | /// conflict with a mutable borrow of `a.b.c`. | |
746 | /// | |
747 | /// This is used when lowering matches: when matching on a place we want to | |
748 | /// ensure that place have the same value from the start of the match until | |
749 | /// an arm is selected. This prevents this code from compiling: | |
04454e1e FG |
750 | /// ```compile_fail,E0510 |
751 | /// let mut x = &Some(0); | |
752 | /// match *x { | |
753 | /// None => (), | |
754 | /// Some(_) if { x = &None; false } => (), | |
755 | /// Some(_) => (), | |
756 | /// } | |
757 | /// ``` | |
0bf4aa26 XL |
758 | /// This can't be a shared borrow because mutably borrowing (*x as Some).0 |
759 | /// should not prevent `if let None = x { ... }`, for example, because the | |
760 | /// mutating `(*x as Some).0` can't affect the discriminant of `x`. | |
761 | /// We can also report errors with this kind of borrow differently. | |
762 | Shallow, | |
763 | ||
9fa01778 | 764 | /// Data must be immutable but not aliasable. This kind of borrow |
e9174d1e | 765 | /// cannot currently be expressed by the user and is used only in |
b7449926 XL |
766 | /// implicit closure bindings. It is needed when the closure is |
767 | /// borrowing or mutating a mutable referent, e.g.: | |
04454e1e FG |
768 | /// ``` |
769 | /// let mut z = 3; | |
770 | /// let x: &mut isize = &mut z; | |
771 | /// let y = || *x += 5; | |
772 | /// ``` | |
e9174d1e SL |
773 | /// If we were to try to translate this closure into a more explicit |
774 | /// form, we'd encounter an error with the code as written: | |
04454e1e FG |
775 | /// ```compile_fail,E0594 |
776 | /// struct Env<'a> { x: &'a &'a mut isize } | |
777 | /// let mut z = 3; | |
778 | /// let x: &mut isize = &mut z; | |
779 | /// let y = (&mut Env { x: &x }, fn_ptr); // Closure is pair of env and fn | |
780 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
781 | /// ``` | |
b7449926 | 782 | /// This is then illegal because you cannot mutate an `&mut` found |
e9174d1e SL |
783 | /// in an aliasable location. To solve, you'd have to translate with |
784 | /// an `&mut` borrow: | |
04454e1e FG |
785 | /// ```compile_fail,E0596 |
786 | /// struct Env<'a> { x: &'a mut &'a mut isize } | |
787 | /// let mut z = 3; | |
788 | /// let x: &mut isize = &mut z; | |
789 | /// let y = (&mut Env { x: &mut x }, fn_ptr); // changed from &x to &mut x | |
790 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
791 | /// ``` | |
e9174d1e SL |
792 | /// Now the assignment to `**env.x` is legal, but creating a |
793 | /// mutable pointer to `x` is not because `x` is not mutable. We | |
794 | /// could fix this by declaring `x` as `let mut x`. This is ok in | |
795 | /// user code, if awkward, but extra weird for closures, since the | |
796 | /// borrow is hidden. | |
797 | /// | |
798 | /// So we introduce a "unique imm" borrow -- the referent is | |
799 | /// immutable, but not aliasable. This solves the problem. For | |
800 | /// simplicity, we don't give users the way to express this | |
801 | /// borrow, it's just used when translating closures. | |
802 | Unique, | |
803 | ||
804 | /// Data is mutable and not aliasable. | |
2c00a5a8 | 805 | Mut { |
9fa01778 XL |
806 | /// `true` if this borrow arose from method-call auto-ref |
807 | /// (i.e., `adjustment::Adjust::Borrow`). | |
94b46f34 XL |
808 | allow_two_phase_borrow: bool, |
809 | }, | |
2c00a5a8 XL |
810 | } |
811 | ||
812 | impl BorrowKind { | |
813 | pub fn allows_two_phase_borrow(&self) -> bool { | |
814 | match *self { | |
0bf4aa26 XL |
815 | BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, |
816 | BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, | |
2c00a5a8 XL |
817 | } |
818 | } | |
17df50a5 XL |
819 | |
820 | pub fn describe_mutability(&self) -> String { | |
821 | match *self { | |
822 | BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => { | |
823 | "immutable".to_string() | |
824 | } | |
825 | BorrowKind::Mut { .. } => "mutable".to_string(), | |
826 | } | |
827 | } | |
e9174d1e SL |
828 | } |
829 | ||
830 | /////////////////////////////////////////////////////////////////////////// | |
831 | // Variables and temps | |
832 | ||
e74abb32 | 833 | rustc_index::newtype_index! { |
b7449926 | 834 | pub struct Local { |
532ac7d7 | 835 | derive [HashStable] |
abe05a73 | 836 | DEBUG_FORMAT = "_{}", |
ff7c6d11 | 837 | const RETURN_PLACE = 0, |
b7449926 XL |
838 | } |
839 | } | |
54a0048b | 840 | |
416331ca XL |
841 | impl Atom for Local { |
842 | fn index(self) -> usize { | |
843 | Idx::index(self) | |
844 | } | |
845 | } | |
846 | ||
dc9dc135 | 847 | /// Classifies locals into categories. See `Body::local_kind`. |
1b1a35ee | 848 | #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] |
c30ab7b3 | 849 | pub enum LocalKind { |
e1599b0c | 850 | /// User-declared variable binding. |
c30ab7b3 | 851 | Var, |
e1599b0c | 852 | /// Compiler-introduced temporary. |
c30ab7b3 | 853 | Temp, |
e1599b0c | 854 | /// Function argument. |
c30ab7b3 | 855 | Arg, |
e1599b0c | 856 | /// Location of function's return value. |
c30ab7b3 | 857 | ReturnPointer, |
e9174d1e SL |
858 | } |
859 | ||
3dfed10e | 860 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] |
8faf50e0 | 861 | pub struct VarBindingForm<'tcx> { |
94b46f34 XL |
862 | /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? |
863 | pub binding_mode: ty::BindingMode, | |
864 | /// If an explicit type was provided for this variable binding, | |
865 | /// this holds the source Span of that type. | |
866 | /// | |
9fa01778 | 867 | /// NOTE: if you want to change this to a `HirId`, be wary that |
94b46f34 XL |
868 | /// doing so breaks incremental compilation (as of this writing), |
869 | /// while a `Span` does not cause our tests to fail. | |
870 | pub opt_ty_info: Option<Span>, | |
8faf50e0 XL |
871 | /// Place of the RHS of the =, or the subject of the `match` where this |
872 | /// variable is initialized. None in the case of `let PATTERN;`. | |
873 | /// Some((None, ..)) in the case of and `let [mut] x = ...` because | |
874 | /// (a) the right-hand side isn't evaluated as a place expression. | |
875 | /// (b) it gives a way to separate this case from the remaining cases | |
876 | /// for diagnostics. | |
877 | pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>, | |
e1599b0c | 878 | /// The span of the pattern in which this variable was bound. |
b7449926 | 879 | pub pat_span: Span, |
94b46f34 XL |
880 | } |
881 | ||
3dfed10e | 882 | #[derive(Clone, Debug, TyEncodable, TyDecodable)] |
8faf50e0 | 883 | pub enum BindingForm<'tcx> { |
94b46f34 | 884 | /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. |
8faf50e0 | 885 | Var(VarBindingForm<'tcx>), |
94b46f34 | 886 | /// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit. |
0bf4aa26 | 887 | ImplicitSelf(ImplicitSelfKind), |
8faf50e0 XL |
888 | /// Reference used in a guard expression to ensure immutability. |
889 | RefForGuard, | |
94b46f34 XL |
890 | } |
891 | ||
0bf4aa26 | 892 | /// Represents what type of implicit self a function has, if any. |
3dfed10e | 893 | #[derive(Clone, Copy, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] |
0bf4aa26 XL |
894 | pub enum ImplicitSelfKind { |
895 | /// Represents a `fn x(self);`. | |
896 | Imm, | |
897 | /// Represents a `fn x(mut self);`. | |
898 | Mut, | |
899 | /// Represents a `fn x(&self);`. | |
900 | ImmRef, | |
901 | /// Represents a `fn x(&mut self);`. | |
902 | MutRef, | |
903 | /// Represents when a function does not have a self argument or | |
904 | /// when a function has a `self: X` argument. | |
416331ca | 905 | None, |
0bf4aa26 XL |
906 | } |
907 | ||
fc512014 | 908 | TrivialTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } |
94b46f34 | 909 | |
8faf50e0 | 910 | mod binding_form_impl { |
e74abb32 | 911 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
c295e0f8 | 912 | use rustc_query_system::ich::StableHashingContext; |
8faf50e0 XL |
913 | |
914 | impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> { | |
e74abb32 | 915 | fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { |
8faf50e0 | 916 | use super::BindingForm::*; |
29967ef6 | 917 | std::mem::discriminant(self).hash_stable(hcx, hasher); |
8faf50e0 XL |
918 | |
919 | match self { | |
920 | Var(binding) => binding.hash_stable(hcx, hasher), | |
0bf4aa26 | 921 | ImplicitSelf(kind) => kind.hash_stable(hcx, hasher), |
8faf50e0 XL |
922 | RefForGuard => (), |
923 | } | |
924 | } | |
925 | } | |
926 | } | |
94b46f34 | 927 | |
0bf4aa26 XL |
928 | /// `BlockTailInfo` is attached to the `LocalDecl` for temporaries |
929 | /// created during evaluation of expressions in a block tail | |
930 | /// expression; that is, a block like `{ STMT_1; STMT_2; EXPR }`. | |
931 | /// | |
932 | /// It is used to improve diagnostics when such temporaries are | |
0731742a | 933 | /// involved in borrow_check errors, e.g., explanations of where the |
0bf4aa26 XL |
934 | /// temporaries come from, when their destructors are run, and/or how |
935 | /// one might revise the code to satisfy the borrow checker's rules. | |
3dfed10e | 936 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] |
0bf4aa26 XL |
937 | pub struct BlockTailInfo { |
938 | /// If `true`, then the value resulting from evaluating this tail | |
939 | /// expression is ignored by the block's expression context. | |
940 | /// | |
941 | /// Examples include `{ ...; tail };` and `let _ = { ...; tail };` | |
0731742a | 942 | /// but not e.g., `let _x = { ...; tail };` |
0bf4aa26 | 943 | pub tail_result_is_ignored: bool, |
f9f354fc XL |
944 | |
945 | /// `Span` of the tail expression. | |
946 | pub span: Span, | |
0bf4aa26 XL |
947 | } |
948 | ||
c30ab7b3 | 949 | /// A MIR local. |
7453a54e | 950 | /// |
c30ab7b3 | 951 | /// This can be a binding declared by the user, a temporary inserted by the compiler, a function |
ff7c6d11 | 952 | /// argument, or the return place. |
3dfed10e | 953 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
c30ab7b3 | 954 | pub struct LocalDecl<'tcx> { |
29967ef6 | 955 | /// Whether this is a mutable binding (i.e., `let x` or `let mut x`). |
c30ab7b3 | 956 | /// |
ff7c6d11 | 957 | /// Temporaries and the return place are always mutable. |
c30ab7b3 SL |
958 | pub mutability: Mutability, |
959 | ||
60c5eb7d | 960 | // FIXME(matthewjasper) Don't store in this in `Body` |
f9f354fc | 961 | pub local_info: Option<Box<LocalInfo<'tcx>>>, |
cc61c64b | 962 | |
9fa01778 | 963 | /// `true` if this is an internal local. |
ea8adc8c XL |
964 | /// |
965 | /// These locals are not based on types in the source code and are only used | |
966 | /// for a few desugarings at the moment. | |
967 | /// | |
968 | /// The generator transformation will sanity check the locals which are live | |
969 | /// across a suspension point against the type components of the generator | |
970 | /// which type checking knows are live across a suspension point. We need to | |
971 | /// flag drop flags to avoid triggering this check as they are introduced | |
5099ac24 | 972 | /// outside of type inference. |
ea8adc8c | 973 | /// |
ea8adc8c | 974 | /// This should be sound because the drop flags are fully algebraic, and |
fc512014 | 975 | /// therefore don't affect the auto-trait or outlives properties of the |
ea8adc8c XL |
976 | /// generator. |
977 | pub internal: bool, | |
978 | ||
0bf4aa26 XL |
979 | /// If this local is a temporary and `is_block_tail` is `Some`, |
980 | /// then it is a temporary created for evaluation of some | |
981 | /// subexpression of some block's tail expression (with no | |
982 | /// intervening statement context). | |
60c5eb7d | 983 | // FIXME(matthewjasper) Don't store in this in `Body` |
0bf4aa26 XL |
984 | pub is_block_tail: Option<BlockTailInfo>, |
985 | ||
e1599b0c | 986 | /// The type of this local. |
b039eaaf | 987 | pub ty: Ty<'tcx>, |
54a0048b | 988 | |
b7449926 | 989 | /// If the user manually ascribed a type to this variable, |
0731742a | 990 | /// e.g., via `let x: T`, then we carry that type here. The MIR |
b7449926 XL |
991 | /// borrow checker needs this information since it can affect |
992 | /// region inference. | |
60c5eb7d | 993 | // FIXME(matthewjasper) Don't store in this in `Body` |
f9f354fc | 994 | pub user_ty: Option<Box<UserTypeProjections>>, |
b7449926 | 995 | |
0731742a | 996 | /// The *syntactic* (i.e., not visibility) source scope the local is defined |
ea8adc8c XL |
997 | /// in. If the local was defined in a let-statement, this |
998 | /// is *within* the let-statement, rather than outside | |
999 | /// of it. | |
ff7c6d11 | 1000 | /// |
94b46f34 XL |
1001 | /// This is needed because the visibility source scope of locals within |
1002 | /// a let-statement is weird. | |
ff7c6d11 XL |
1003 | /// |
1004 | /// The reason is that we want the local to be *within* the let-statement | |
1005 | /// for lint purposes, but we want the local to be *after* the let-statement | |
1006 | /// for names-in-scope purposes. | |
1007 | /// | |
1008 | /// That's it, if we have a let-statement like the one in this | |
1009 | /// function: | |
1010 | /// | |
1011 | /// ``` | |
1012 | /// fn foo(x: &str) { | |
1013 | /// #[allow(unused_mut)] | |
1014 | /// let mut x: u32 = { // <- one unused mut | |
1015 | /// let mut y: u32 = x.parse().unwrap(); | |
1016 | /// y + 2 | |
1017 | /// }; | |
1018 | /// drop(x); | |
1019 | /// } | |
1020 | /// ``` | |
1021 | /// | |
1022 | /// Then, from a lint point of view, the declaration of `x: u32` | |
1023 | /// (and `y: u32`) are within the `#[allow(unused_mut)]` scope - the | |
1024 | /// lint scopes are the same as the AST/HIR nesting. | |
1025 | /// | |
1026 | /// However, from a name lookup point of view, the scopes look more like | |
1027 | /// as if the let-statements were `match` expressions: | |
1028 | /// | |
1029 | /// ``` | |
1030 | /// fn foo(x: &str) { | |
1031 | /// match { | |
04454e1e | 1032 | /// match x.parse::<u32>().unwrap() { |
ff7c6d11 XL |
1033 | /// y => y + 2 |
1034 | /// } | |
1035 | /// } { | |
1036 | /// x => drop(x) | |
1037 | /// }; | |
1038 | /// } | |
1039 | /// ``` | |
1040 | /// | |
1041 | /// We care about the name-lookup scopes for debuginfo - if the | |
1042 | /// debuginfo instruction pointer is at the call to `x.parse()`, we | |
1043 | /// want `x` to refer to `x: &str`, but if it is at the call to | |
1044 | /// `drop(x)`, we want it to refer to `x: u32`. | |
1045 | /// | |
1046 | /// To allow both uses to work, we need to have more than a single scope | |
60c5eb7d XL |
1047 | /// for a local. We have the `source_info.scope` represent the "syntactic" |
1048 | /// lint scope (with a variable being under its let block) while the | |
1049 | /// `var_debug_info.source_info.scope` represents the "local variable" | |
ff7c6d11 XL |
1050 | /// scope (where the "rest" of a block is under all prior let-statements). |
1051 | /// | |
1052 | /// The end result looks like this: | |
1053 | /// | |
1054 | /// ```text | |
1055 | /// ROOT SCOPE | |
1056 | /// │{ argument x: &str } | |
1057 | /// │ | |
e1599b0c XL |
1058 | /// │ │{ #[allow(unused_mut)] } // This is actually split into 2 scopes |
1059 | /// │ │ // in practice because I'm lazy. | |
ff7c6d11 | 1060 | /// │ │ |
94b46f34 | 1061 | /// │ │← x.source_info.scope |
ff7c6d11 XL |
1062 | /// │ │← `x.parse().unwrap()` |
1063 | /// │ │ | |
94b46f34 | 1064 | /// │ │ │← y.source_info.scope |
ff7c6d11 XL |
1065 | /// │ │ |
1066 | /// │ │ │{ let y: u32 } | |
1067 | /// │ │ │ | |
60c5eb7d | 1068 | /// │ │ │← y.var_debug_info.source_info.scope |
ff7c6d11 XL |
1069 | /// │ │ │← `y + 2` |
1070 | /// │ | |
1071 | /// │ │{ let x: u32 } | |
60c5eb7d | 1072 | /// │ │← x.var_debug_info.source_info.scope |
e1599b0c | 1073 | /// │ │← `drop(x)` // This accesses `x: u32`. |
ff7c6d11 | 1074 | /// ``` |
94b46f34 | 1075 | pub source_info: SourceInfo, |
60c5eb7d | 1076 | } |
94b46f34 | 1077 | |
f9f354fc | 1078 | // `LocalDecl` is used a lot. Make sure it doesn't unintentionally get bigger. |
6a06907d | 1079 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
f9f354fc XL |
1080 | static_assert_size!(LocalDecl<'_>, 56); |
1081 | ||
3dfed10e XL |
1082 | /// Extra information about a some locals that's used for diagnostics and for |
1083 | /// classifying variables into local variables, statics, etc, which is needed e.g. | |
1084 | /// for unsafety checking. | |
1085 | /// | |
1086 | /// Not used for non-StaticRef temporaries, the return place, or anonymous | |
1087 | /// function parameters. | |
1088 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] | |
60c5eb7d XL |
1089 | pub enum LocalInfo<'tcx> { |
1090 | /// A user-defined local variable or function parameter | |
1091 | /// | |
1092 | /// The `BindingForm` is solely used for local diagnostics when generating | |
1093 | /// warnings/errors when compiling the current crate, and therefore it need | |
1094 | /// not be visible across crates. | |
1095 | User(ClearCrossCrate<BindingForm<'tcx>>), | |
1096 | /// A temporary created that references the static with the given `DefId`. | |
1097 | StaticRef { def_id: DefId, is_thread_local: bool }, | |
1b1a35ee XL |
1098 | /// A temporary created that references the const with the given `DefId` |
1099 | ConstRef { def_id: DefId }, | |
c295e0f8 XL |
1100 | /// A temporary created during the creation of an aggregate |
1101 | /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`) | |
1102 | AggregateTemp, | |
04454e1e FG |
1103 | /// A temporary created during the pass `Derefer` to avoid it's retagging |
1104 | DerefTemp, | |
c30ab7b3 SL |
1105 | } |
1106 | ||
1107 | impl<'tcx> LocalDecl<'tcx> { | |
9fa01778 | 1108 | /// Returns `true` only if local is a binding that can itself be |
94b46f34 XL |
1109 | /// made mutable via the addition of the `mut` keyword, namely |
1110 | /// something like the occurrences of `x` in: | |
1111 | /// - `fn foo(x: Type) { ... }`, | |
1112 | /// - `let x = ...`, | |
1113 | /// - or `match ... { C(x) => ... }` | |
1114 | pub fn can_be_made_mutable(&self) -> bool { | |
29967ef6 XL |
1115 | matches!( |
1116 | self.local_info, | |
1117 | Some(box LocalInfo::User(ClearCrossCrate::Set( | |
1118 | BindingForm::Var(VarBindingForm { | |
1119 | binding_mode: ty::BindingMode::BindByValue(_), | |
1120 | opt_ty_info: _, | |
1121 | opt_match_place: _, | |
1122 | pat_span: _, | |
5869c6ff | 1123 | }) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm), |
29967ef6 XL |
1124 | ))) |
1125 | ) | |
94b46f34 XL |
1126 | } |
1127 | ||
9fa01778 | 1128 | /// Returns `true` if local is definitely not a `ref ident` or |
94b46f34 XL |
1129 | /// `ref mut ident` binding. (Such bindings cannot be made into |
1130 | /// mutable bindings, but the inverse does not necessarily hold). | |
1131 | pub fn is_nonref_binding(&self) -> bool { | |
29967ef6 XL |
1132 | matches!( |
1133 | self.local_info, | |
1134 | Some(box LocalInfo::User(ClearCrossCrate::Set( | |
1135 | BindingForm::Var(VarBindingForm { | |
1136 | binding_mode: ty::BindingMode::BindByValue(_), | |
1137 | opt_ty_info: _, | |
1138 | opt_match_place: _, | |
1139 | pat_span: _, | |
5869c6ff | 1140 | }) | BindingForm::ImplicitSelf(_), |
29967ef6 XL |
1141 | ))) |
1142 | ) | |
60c5eb7d | 1143 | } |
94b46f34 | 1144 | |
60c5eb7d XL |
1145 | /// Returns `true` if this variable is a named variable or function |
1146 | /// parameter declared by the user. | |
1147 | #[inline] | |
1148 | pub fn is_user_variable(&self) -> bool { | |
29967ef6 | 1149 | matches!(self.local_info, Some(box LocalInfo::User(_))) |
94b46f34 XL |
1150 | } |
1151 | ||
dc9dc135 XL |
1152 | /// Returns `true` if this is a reference to a variable bound in a `match` |
1153 | /// expression that is used to access said variable for the guard of the | |
1154 | /// match arm. | |
1155 | pub fn is_ref_for_guard(&self) -> bool { | |
29967ef6 XL |
1156 | matches!( |
1157 | self.local_info, | |
1158 | Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) | |
1159 | ) | |
60c5eb7d XL |
1160 | } |
1161 | ||
1162 | /// Returns `Some` if this is a reference to a static item that is used to | |
29967ef6 | 1163 | /// access that static. |
60c5eb7d | 1164 | pub fn is_ref_to_static(&self) -> bool { |
29967ef6 | 1165 | matches!(self.local_info, Some(box LocalInfo::StaticRef { .. })) |
60c5eb7d XL |
1166 | } |
1167 | ||
29967ef6 XL |
1168 | /// Returns `Some` if this is a reference to a thread-local static item that is used to |
1169 | /// access that static. | |
60c5eb7d XL |
1170 | pub fn is_ref_to_thread_local(&self) -> bool { |
1171 | match self.local_info { | |
f9f354fc | 1172 | Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local, |
dc9dc135 XL |
1173 | _ => false, |
1174 | } | |
1175 | } | |
1176 | ||
1177 | /// Returns `true` is the local is from a compiler desugaring, e.g., | |
1178 | /// `__next` from a `for` loop. | |
1179 | #[inline] | |
1180 | pub fn from_compiler_desugaring(&self) -> bool { | |
416331ca | 1181 | self.source_info.span.desugaring_kind().is_some() |
dc9dc135 XL |
1182 | } |
1183 | ||
f9f354fc | 1184 | /// Creates a new `LocalDecl` for a temporary: mutable, non-internal. |
c30ab7b3 | 1185 | #[inline] |
f9f354fc XL |
1186 | pub fn new(ty: Ty<'tcx>, span: Span) -> Self { |
1187 | Self::with_source_info(ty, SourceInfo::outermost(span)) | |
1188 | } | |
1189 | ||
1190 | /// Like `LocalDecl::new`, but takes a `SourceInfo` instead of a `Span`. | |
1191 | #[inline] | |
1192 | pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self { | |
1193 | LocalDecl { | |
1194 | mutability: Mutability::Mut, | |
1195 | local_info: None, | |
1196 | internal: false, | |
1197 | is_block_tail: None, | |
1198 | ty, | |
1199 | user_ty: None, | |
1200 | source_info, | |
1201 | } | |
1202 | } | |
1203 | ||
1204 | /// Converts `self` into same `LocalDecl` except tagged as internal. | |
1205 | #[inline] | |
1206 | pub fn internal(mut self) -> Self { | |
1207 | self.internal = true; | |
1208 | self | |
b7449926 XL |
1209 | } |
1210 | ||
0bf4aa26 | 1211 | /// Converts `self` into same `LocalDecl` except tagged as immutable. |
b7449926 | 1212 | #[inline] |
0bf4aa26 XL |
1213 | pub fn immutable(mut self) -> Self { |
1214 | self.mutability = Mutability::Not; | |
1215 | self | |
1216 | } | |
1217 | ||
1218 | /// Converts `self` into same `LocalDecl` except tagged as internal temporary. | |
1219 | #[inline] | |
1220 | pub fn block_tail(mut self, info: BlockTailInfo) -> Self { | |
1221 | assert!(self.is_block_tail.is_none()); | |
1222 | self.is_block_tail = Some(info); | |
1223 | self | |
ea8adc8c | 1224 | } |
a7813a04 XL |
1225 | } |
1226 | ||
fc512014 XL |
1227 | #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
1228 | pub enum VarDebugInfoContents<'tcx> { | |
1229 | /// NOTE(eddyb) There's an unenforced invariant that this `Place` is | |
1230 | /// based on a `Local`, not a `Static`, and contains no indexing. | |
1231 | Place(Place<'tcx>), | |
1232 | Const(Constant<'tcx>), | |
1233 | } | |
1234 | ||
1235 | impl<'tcx> Debug for VarDebugInfoContents<'tcx> { | |
1236 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { | |
1237 | match self { | |
1238 | VarDebugInfoContents::Const(c) => write!(fmt, "{}", c), | |
1239 | VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p), | |
1240 | } | |
1241 | } | |
1242 | } | |
1243 | ||
60c5eb7d | 1244 | /// Debug information pertaining to a user variable. |
3dfed10e | 1245 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
60c5eb7d | 1246 | pub struct VarDebugInfo<'tcx> { |
f9f354fc | 1247 | pub name: Symbol, |
60c5eb7d XL |
1248 | |
1249 | /// Source info of the user variable, including the scope | |
1250 | /// within which the variable is visible (to debuginfo) | |
1251 | /// (see `LocalDecl`'s `source_info` field for more details). | |
1252 | pub source_info: SourceInfo, | |
a7813a04 | 1253 | |
60c5eb7d | 1254 | /// Where the data for this user variable is to be found. |
fc512014 | 1255 | pub value: VarDebugInfoContents<'tcx>, |
e9174d1e SL |
1256 | } |
1257 | ||
e9174d1e SL |
1258 | /////////////////////////////////////////////////////////////////////////// |
1259 | // BasicBlock | |
1260 | ||
e74abb32 | 1261 | rustc_index::newtype_index! { |
1b1a35ee XL |
1262 | /// A node in the MIR [control-flow graph][CFG]. |
1263 | /// | |
1264 | /// There are no branches (e.g., `if`s, function calls, etc.) within a basic block, which makes | |
1265 | /// it easier to do [data-flow analyses] and optimizations. Instead, branches are represented | |
1266 | /// as an edge in a graph between basic blocks. | |
1267 | /// | |
1268 | /// Basic blocks consist of a series of [statements][Statement], ending with a | |
1269 | /// [terminator][Terminator]. Basic blocks can have multiple predecessors and successors, | |
1270 | /// however there is a MIR pass ([`CriticalCallEdges`]) that removes *critical edges*, which | |
1271 | /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is | |
1272 | /// needed because some analyses require that there are no critical edges in the CFG. | |
1273 | /// | |
29967ef6 XL |
1274 | /// Note that this type is just an index into [`Body.basic_blocks`](Body::basic_blocks); |
1275 | /// the actual data that a basic block holds is in [`BasicBlockData`]. | |
1276 | /// | |
1b1a35ee XL |
1277 | /// Read more about basic blocks in the [rustc-dev-guide][guide-mir]. |
1278 | /// | |
1279 | /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg | |
1280 | /// [data-flow analyses]: | |
1281 | /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis | |
c295e0f8 | 1282 | /// [`CriticalCallEdges`]: ../../rustc_const_eval/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges |
1b1a35ee | 1283 | /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/ |
b7449926 | 1284 | pub struct BasicBlock { |
532ac7d7 | 1285 | derive [HashStable] |
b7449926 XL |
1286 | DEBUG_FORMAT = "bb{}", |
1287 | const START_BLOCK = 0, | |
1288 | } | |
1289 | } | |
abe05a73 XL |
1290 | |
1291 | impl BasicBlock { | |
1292 | pub fn start_location(self) -> Location { | |
416331ca | 1293 | Location { block: self, statement_index: 0 } |
abe05a73 XL |
1294 | } |
1295 | } | |
e9174d1e SL |
1296 | |
1297 | /////////////////////////////////////////////////////////////////////////// | |
54a0048b | 1298 | // BasicBlockData and Terminator |
e9174d1e | 1299 | |
1b1a35ee | 1300 | /// See [`BasicBlock`] for documentation on what basic blocks are at a high level. |
3dfed10e | 1301 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
b039eaaf | 1302 | pub struct BasicBlockData<'tcx> { |
54a0048b | 1303 | /// List of statements in this block. |
b039eaaf | 1304 | pub statements: Vec<Statement<'tcx>>, |
54a0048b SL |
1305 | |
1306 | /// Terminator for this block. | |
1307 | /// | |
9fa01778 | 1308 | /// N.B., this should generally ONLY be `None` during construction. |
54a0048b SL |
1309 | /// Therefore, you should generally access it via the |
1310 | /// `terminator()` or `terminator_mut()` methods. The only | |
1311 | /// exception is that certain passes, such as `simplify_cfg`, swap | |
1312 | /// out the terminator temporarily with `None` while they continue | |
1313 | /// to recurse over the set of basic blocks. | |
9cc50fc6 | 1314 | pub terminator: Option<Terminator<'tcx>>, |
54a0048b SL |
1315 | |
1316 | /// If true, this block lies on an unwind path. This is used | |
94b46f34 | 1317 | /// during codegen where distinct kinds of basic blocks may be |
54a0048b SL |
1318 | /// generated (particularly for MSVC cleanup). Unwind blocks must |
1319 | /// only branch to other unwind blocks. | |
9cc50fc6 | 1320 | pub is_cleanup: bool, |
e9174d1e SL |
1321 | } |
1322 | ||
74b04a01 | 1323 | /// Information about an assertion failure. |
6a06907d | 1324 | #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] |
74b04a01 XL |
1325 | pub enum AssertKind<O> { |
1326 | BoundsCheck { len: O, index: O }, | |
f035d41b XL |
1327 | Overflow(BinOp, O, O), |
1328 | OverflowNeg(O), | |
1329 | DivisionByZero(O), | |
1330 | RemainderByZero(O), | |
74b04a01 XL |
1331 | ResumedAfterReturn(GeneratorKind), |
1332 | ResumedAfterPanic(GeneratorKind), | |
1333 | } | |
1334 | ||
5099ac24 | 1335 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] |
f9f354fc XL |
1336 | pub enum InlineAsmOperand<'tcx> { |
1337 | In { | |
1338 | reg: InlineAsmRegOrRegClass, | |
1339 | value: Operand<'tcx>, | |
1340 | }, | |
1341 | Out { | |
1342 | reg: InlineAsmRegOrRegClass, | |
1343 | late: bool, | |
1344 | place: Option<Place<'tcx>>, | |
1345 | }, | |
1346 | InOut { | |
1347 | reg: InlineAsmRegOrRegClass, | |
1348 | late: bool, | |
1349 | in_value: Operand<'tcx>, | |
1350 | out_place: Option<Place<'tcx>>, | |
1351 | }, | |
1352 | Const { | |
cdc7bbd5 | 1353 | value: Box<Constant<'tcx>>, |
f9f354fc XL |
1354 | }, |
1355 | SymFn { | |
1356 | value: Box<Constant<'tcx>>, | |
1357 | }, | |
1358 | SymStatic { | |
f035d41b | 1359 | def_id: DefId, |
f9f354fc XL |
1360 | }, |
1361 | } | |
1362 | ||
74b04a01 XL |
1363 | /// Type for MIR `Assert` terminator error messages. |
1364 | pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; | |
1365 | ||
923072b8 | 1366 | pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a; |
83c7162d XL |
1367 | pub type SuccessorsMut<'a> = |
1368 | iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; | |
1369 | ||
b039eaaf | 1370 | impl<'tcx> BasicBlockData<'tcx> { |
9cc50fc6 | 1371 | pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> { |
416331ca | 1372 | BasicBlockData { statements: vec![], terminator, is_cleanup: false } |
e9174d1e | 1373 | } |
9cc50fc6 SL |
1374 | |
1375 | /// Accessor for terminator. | |
1376 | /// | |
1377 | /// Terminator may not be None after construction of the basic block is complete. This accessor | |
1378 | /// provides a convenience way to reach the terminator. | |
17df50a5 | 1379 | #[inline] |
9cc50fc6 SL |
1380 | pub fn terminator(&self) -> &Terminator<'tcx> { |
1381 | self.terminator.as_ref().expect("invalid terminator state") | |
1382 | } | |
1383 | ||
17df50a5 | 1384 | #[inline] |
9cc50fc6 SL |
1385 | pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { |
1386 | self.terminator.as_mut().expect("invalid terminator state") | |
1387 | } | |
ea8adc8c | 1388 | |
94b46f34 XL |
1389 | pub fn retain_statements<F>(&mut self, mut f: F) |
1390 | where | |
0bf4aa26 | 1391 | F: FnMut(&mut Statement<'_>) -> bool, |
94b46f34 | 1392 | { |
ea8adc8c XL |
1393 | for s in &mut self.statements { |
1394 | if !f(s) { | |
0531ce1d | 1395 | s.make_nop(); |
ea8adc8c XL |
1396 | } |
1397 | } | |
1398 | } | |
ff7c6d11 | 1399 | |
0531ce1d | 1400 | pub fn expand_statements<F, I>(&mut self, mut f: F) |
94b46f34 XL |
1401 | where |
1402 | F: FnMut(&mut Statement<'tcx>) -> Option<I>, | |
1403 | I: iter::TrustedLen<Item = Statement<'tcx>>, | |
0531ce1d XL |
1404 | { |
1405 | // Gather all the iterators we'll need to splice in, and their positions. | |
1406 | let mut splices: Vec<(usize, I)> = vec![]; | |
1407 | let mut extra_stmts = 0; | |
1408 | for (i, s) in self.statements.iter_mut().enumerate() { | |
1409 | if let Some(mut new_stmts) = f(s) { | |
1410 | if let Some(first) = new_stmts.next() { | |
1411 | // We can already store the first new statement. | |
1412 | *s = first; | |
1413 | ||
1414 | // Save the other statements for optimized splicing. | |
1415 | let remaining = new_stmts.size_hint().0; | |
1416 | if remaining > 0 { | |
1417 | splices.push((i + 1 + extra_stmts, new_stmts)); | |
1418 | extra_stmts += remaining; | |
1419 | } | |
1420 | } else { | |
1421 | s.make_nop(); | |
1422 | } | |
1423 | } | |
1424 | } | |
1425 | ||
1426 | // Splice in the new statements, from the end of the block. | |
1427 | // FIXME(eddyb) This could be more efficient with a "gap buffer" | |
1428 | // where a range of elements ("gap") is left uninitialized, with | |
1429 | // splicing adding new elements to the end of that gap and moving | |
1430 | // existing elements from before the gap to the end of the gap. | |
1431 | // For now, this is safe code, emulating a gap but initializing it. | |
94b46f34 XL |
1432 | let mut gap = self.statements.len()..self.statements.len() + extra_stmts; |
1433 | self.statements.resize( | |
1434 | gap.end, | |
f9f354fc | 1435 | Statement { source_info: SourceInfo::outermost(DUMMY_SP), kind: StatementKind::Nop }, |
94b46f34 | 1436 | ); |
0531ce1d XL |
1437 | for (splice_start, new_stmts) in splices.into_iter().rev() { |
1438 | let splice_end = splice_start + new_stmts.size_hint().0; | |
1439 | while gap.end > splice_end { | |
1440 | gap.start -= 1; | |
1441 | gap.end -= 1; | |
1442 | self.statements.swap(gap.start, gap.end); | |
1443 | } | |
1444 | self.statements.splice(splice_start..splice_end, new_stmts); | |
1445 | gap.end = splice_start; | |
1446 | } | |
1447 | } | |
1448 | ||
ff7c6d11 | 1449 | pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { |
dfeec247 | 1450 | if index < self.statements.len() { &self.statements[index] } else { &self.terminator } |
ff7c6d11 | 1451 | } |
e9174d1e SL |
1452 | } |
1453 | ||
74b04a01 XL |
1454 | impl<O> AssertKind<O> { |
1455 | /// Getting a description does not require `O` to be printable, and does not | |
1456 | /// require allocation. | |
1457 | /// The caller is expected to handle `BoundsCheck` separately. | |
1458 | pub fn description(&self) -> &'static str { | |
1459 | use AssertKind::*; | |
1460 | match self { | |
f035d41b XL |
1461 | Overflow(BinOp::Add, _, _) => "attempt to add with overflow", |
1462 | Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow", | |
1463 | Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow", | |
1464 | Overflow(BinOp::Div, _, _) => "attempt to divide with overflow", | |
1465 | Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow", | |
1466 | OverflowNeg(_) => "attempt to negate with overflow", | |
1467 | Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow", | |
1468 | Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow", | |
1469 | Overflow(op, _, _) => bug!("{:?} cannot overflow", op), | |
1470 | DivisionByZero(_) => "attempt to divide by zero", | |
1471 | RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero", | |
74b04a01 XL |
1472 | ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion", |
1473 | ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion", | |
1474 | ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking", | |
1475 | ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking", | |
1476 | BoundsCheck { .. } => bug!("Unexpected AssertKind"), | |
1477 | } | |
1478 | } | |
ba9703b0 XL |
1479 | |
1480 | /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing. | |
17df50a5 | 1481 | pub fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result |
ba9703b0 XL |
1482 | where |
1483 | O: Debug, | |
1484 | { | |
f035d41b | 1485 | use AssertKind::*; |
ba9703b0 | 1486 | match self { |
f035d41b | 1487 | BoundsCheck { ref len, ref index } => write!( |
ba9703b0 | 1488 | f, |
1b1a35ee | 1489 | "\"index out of bounds: the length is {{}} but the index is {{}}\", {:?}, {:?}", |
ba9703b0 XL |
1490 | len, index |
1491 | ), | |
f035d41b XL |
1492 | |
1493 | OverflowNeg(op) => { | |
1b1a35ee | 1494 | write!(f, "\"attempt to negate `{{}}`, which would overflow\", {:?}", op) |
f035d41b | 1495 | } |
1b1a35ee | 1496 | DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {:?}", op), |
f035d41b XL |
1497 | RemainderByZero(op) => write!( |
1498 | f, | |
1b1a35ee | 1499 | "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {:?}", |
f035d41b XL |
1500 | op |
1501 | ), | |
1502 | Overflow(BinOp::Add, l, r) => write!( | |
1503 | f, | |
1b1a35ee | 1504 | "\"attempt to compute `{{}} + {{}}`, which would overflow\", {:?}, {:?}", |
f035d41b XL |
1505 | l, r |
1506 | ), | |
1507 | Overflow(BinOp::Sub, l, r) => write!( | |
1508 | f, | |
1b1a35ee | 1509 | "\"attempt to compute `{{}} - {{}}`, which would overflow\", {:?}, {:?}", |
f035d41b XL |
1510 | l, r |
1511 | ), | |
1512 | Overflow(BinOp::Mul, l, r) => write!( | |
1513 | f, | |
1b1a35ee | 1514 | "\"attempt to compute `{{}} * {{}}`, which would overflow\", {:?}, {:?}", |
f035d41b XL |
1515 | l, r |
1516 | ), | |
1517 | Overflow(BinOp::Div, l, r) => write!( | |
1518 | f, | |
1b1a35ee | 1519 | "\"attempt to compute `{{}} / {{}}`, which would overflow\", {:?}, {:?}", |
f035d41b XL |
1520 | l, r |
1521 | ), | |
1522 | Overflow(BinOp::Rem, l, r) => write!( | |
1523 | f, | |
1b1a35ee | 1524 | "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {:?}, {:?}", |
f035d41b XL |
1525 | l, r |
1526 | ), | |
1527 | Overflow(BinOp::Shr, _, r) => { | |
1b1a35ee | 1528 | write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {:?}", r) |
f035d41b XL |
1529 | } |
1530 | Overflow(BinOp::Shl, _, r) => { | |
1b1a35ee | 1531 | write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {:?}", r) |
f035d41b | 1532 | } |
ba9703b0 XL |
1533 | _ => write!(f, "\"{}\"", self.description()), |
1534 | } | |
1535 | } | |
74b04a01 XL |
1536 | } |
1537 | ||
1538 | impl<O: fmt::Debug> fmt::Debug for AssertKind<O> { | |
1539 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
1540 | use AssertKind::*; | |
1541 | match self { | |
1b1a35ee XL |
1542 | BoundsCheck { ref len, ref index } => write!( |
1543 | f, | |
1544 | "index out of bounds: the length is {:?} but the index is {:?}", | |
1545 | len, index | |
1546 | ), | |
1547 | OverflowNeg(op) => write!(f, "attempt to negate `{:#?}`, which would overflow", op), | |
1548 | DivisionByZero(op) => write!(f, "attempt to divide `{:#?}` by zero", op), | |
1549 | RemainderByZero(op) => write!( | |
1550 | f, | |
1551 | "attempt to calculate the remainder of `{:#?}` with a divisor of zero", | |
1552 | op | |
1553 | ), | |
f035d41b | 1554 | Overflow(BinOp::Add, l, r) => { |
1b1a35ee | 1555 | write!(f, "attempt to compute `{:#?} + {:#?}`, which would overflow", l, r) |
e9174d1e | 1556 | } |
f035d41b | 1557 | Overflow(BinOp::Sub, l, r) => { |
1b1a35ee | 1558 | write!(f, "attempt to compute `{:#?} - {:#?}`, which would overflow", l, r) |
94b46f34 | 1559 | } |
f035d41b | 1560 | Overflow(BinOp::Mul, l, r) => { |
1b1a35ee | 1561 | write!(f, "attempt to compute `{:#?} * {:#?}`, which would overflow", l, r) |
f9f354fc | 1562 | } |
f035d41b | 1563 | Overflow(BinOp::Div, l, r) => { |
1b1a35ee | 1564 | write!(f, "attempt to compute `{:#?} / {:#?}`, which would overflow", l, r) |
9cc50fc6 | 1565 | } |
f035d41b XL |
1566 | Overflow(BinOp::Rem, l, r) => write!( |
1567 | f, | |
1b1a35ee | 1568 | "attempt to compute the remainder of `{:#?} % {:#?}`, which would overflow", |
f035d41b XL |
1569 | l, r |
1570 | ), | |
1571 | Overflow(BinOp::Shr, _, r) => { | |
1b1a35ee | 1572 | write!(f, "attempt to shift right by `{:#?}`, which would overflow", r) |
94b46f34 | 1573 | } |
f035d41b | 1574 | Overflow(BinOp::Shl, _, r) => { |
1b1a35ee | 1575 | write!(f, "attempt to shift left by `{:#?}`, which would overflow", r) |
3157f602 | 1576 | } |
f035d41b | 1577 | _ => write!(f, "{}", self.description()), |
9cc50fc6 SL |
1578 | } |
1579 | } | |
e9174d1e SL |
1580 | } |
1581 | ||
e9174d1e SL |
1582 | /////////////////////////////////////////////////////////////////////////// |
1583 | // Statements | |
1584 | ||
3dfed10e | 1585 | #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
b039eaaf | 1586 | pub struct Statement<'tcx> { |
3157f602 | 1587 | pub source_info: SourceInfo, |
b039eaaf | 1588 | pub kind: StatementKind<'tcx>, |
e9174d1e SL |
1589 | } |
1590 | ||
a1dfa0c6 | 1591 | // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. |
6a06907d | 1592 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
e1599b0c | 1593 | static_assert_size!(Statement<'_>, 32); |
a1dfa0c6 | 1594 | |
e1599b0c | 1595 | impl Statement<'_> { |
9e0c209e SL |
1596 | /// Changes a statement to a nop. This is both faster than deleting instructions and avoids |
1597 | /// invalidating statement indices in `Location`s. | |
1598 | pub fn make_nop(&mut self) { | |
1599 | self.kind = StatementKind::Nop | |
1600 | } | |
0531ce1d XL |
1601 | |
1602 | /// Changes a statement to a nop and returns the original statement. | |
a2a8927a | 1603 | #[must_use = "If you don't need the statement, use `make_nop` instead"] |
0531ce1d XL |
1604 | pub fn replace_nop(&mut self) -> Self { |
1605 | Statement { | |
1606 | source_info: self.source_info, | |
94b46f34 | 1607 | kind: mem::replace(&mut self.kind, StatementKind::Nop), |
0531ce1d XL |
1608 | } |
1609 | } | |
9e0c209e SL |
1610 | } |
1611 | ||
5e7ed085 FG |
1612 | /// The various kinds of statements that can appear in MIR. |
1613 | /// | |
1614 | /// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which | |
1615 | /// ones you do not have to worry about. The MIR validator will generally enforce such restrictions, | |
1616 | /// causing an ICE if they are violated. | |
6a06907d | 1617 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] |
b039eaaf | 1618 | pub enum StatementKind<'tcx> { |
04454e1e FG |
1619 | /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except |
1620 | /// without the possibility of dropping the previous value (that must be done separately, if at | |
1621 | /// all). The *exact* way this works is undecided. It probably does something like evaluating | |
1622 | /// the LHS to a place and the RHS to a value, and then storing the value to the place. Various | |
1623 | /// parts of this may do type specific things that are more complicated than simply copying | |
1624 | /// bytes. | |
1625 | /// | |
1626 | /// **Needs clarification**: The implication of the above idea would be that assignment implies | |
1627 | /// that the resulting value is initialized. I believe we could commit to this separately from | |
1628 | /// committing to whatever part of the memory model we would need to decide on to make the above | |
1629 | /// paragragh precise. Do we want to? | |
1630 | /// | |
1631 | /// Assignments in which the types of the place and rvalue differ are not well-formed. | |
5e7ed085 | 1632 | /// |
04454e1e FG |
1633 | /// **Needs clarification**: Do we ever want to worry about non-free (in the body) lifetimes for |
1634 | /// the typing requirement in post drop-elaboration MIR? I think probably not - I'm not sure we | |
1635 | /// could meaningfully require this anyway. How about free lifetimes? Is ignoring this | |
1636 | /// interesting for optimizations? Do we want to allow such optimizations? | |
1637 | /// | |
1638 | /// **Needs clarification**: We currently require that the LHS place not overlap with any place | |
1639 | /// read as part of computation of the RHS for some rvalues (generally those not producing | |
1640 | /// primitives). This requirement is under discussion in [#68364]. As a part of this discussion, | |
1641 | /// it is also unclear in what order the components are evaluated. | |
1642 | /// | |
1643 | /// [#68364]: https://github.com/rust-lang/rust/issues/68364 | |
1644 | /// | |
1645 | /// See [`Rvalue`] documentation for details on each of those. | |
e1599b0c | 1646 | Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), |
5bcae85e | 1647 | |
04454e1e FG |
1648 | /// This represents all the reading that a pattern match may do (e.g., inspecting constants and |
1649 | /// discriminant values), and the kind of pattern it comes from. This is in order to adapt | |
1650 | /// potential error messages to these specific patterns. | |
0731742a XL |
1651 | /// |
1652 | /// Note that this also is emitted for regular `let` bindings to ensure that locals that are | |
9fa01778 | 1653 | /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` |
04454e1e FG |
1654 | /// |
1655 | /// When executed at runtime this is a nop. | |
1656 | /// | |
1657 | /// Disallowed after drop elaboration. | |
cdc7bbd5 | 1658 | FakeRead(Box<(FakeReadCause, Place<'tcx>)>), |
94b46f34 | 1659 | |
ff7c6d11 | 1660 | /// Write the discriminant for a variant to the enum Place. |
04454e1e FG |
1661 | /// |
1662 | /// This is permitted for both generators and ADTs. This does not necessarily write to the | |
1663 | /// entire place; instead, it writes to the minimum set of bytes as required by the layout for | |
1664 | /// the type. | |
e1599b0c | 1665 | SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx }, |
5bcae85e | 1666 | |
04454e1e FG |
1667 | /// Deinitializes the place. |
1668 | /// | |
1669 | /// This writes `uninit` bytes to the entire place. | |
1670 | Deinit(Box<Place<'tcx>>), | |
1671 | ||
1672 | /// `StorageLive` and `StorageDead` statements mark the live range of a local. | |
1673 | /// | |
1674 | /// Using a local before a `StorageLive` or after a `StorageDead` is not well-formed. These | |
1675 | /// statements are not required. If the entire MIR body contains no `StorageLive`/`StorageDead` | |
1676 | /// statements for a particular local, the local is always considered live. | |
1677 | /// | |
1678 | /// More precisely, the MIR validator currently does a `MaybeStorageLiveLocals` analysis to | |
1679 | /// check validity of each use of a local. I believe this is equivalent to requiring for every | |
1680 | /// use of a local, there exist at least one path from the root to that use that contains a | |
1681 | /// `StorageLive` more recently than a `StorageDead`. | |
1682 | /// | |
1683 | /// **Needs clarification**: Is it permitted to have two `StorageLive`s without an intervening | |
1684 | /// `StorageDead`? Two `StorageDead`s without an intervening `StorageLive`? LLVM says poison, | |
1685 | /// yes. If the answer to any of these is "no," is breaking that rule UB or is it an error to | |
1686 | /// have a path in the CFG that might do this? | |
ea8adc8c | 1687 | StorageLive(Local), |
5bcae85e | 1688 | |
04454e1e | 1689 | /// See `StorageLive` above. |
ea8adc8c | 1690 | StorageDead(Local), |
9e0c209e | 1691 | |
04454e1e FG |
1692 | /// Retag references in the given place, ensuring they got fresh tags. |
1693 | /// | |
1694 | /// This is part of the Stacked Borrows model. These statements are currently only interpreted | |
1695 | /// by miri and only generated when `-Z mir-emit-retag` is passed. See | |
1696 | /// <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> for | |
1697 | /// more details. | |
1698 | /// | |
1699 | /// For code that is not specific to stacked borrows, you should consider retags to read | |
1700 | /// and modify the place in an opaque way. | |
e1599b0c | 1701 | Retag(RetagKind, Box<Place<'tcx>>), |
041b39d2 | 1702 | |
b7449926 XL |
1703 | /// Encodes a user's type ascription. These need to be preserved |
1704 | /// intact so that NLL can respect them. For example: | |
04454e1e FG |
1705 | /// ```ignore (illustrative) |
1706 | /// let a: T = y; | |
1707 | /// ``` | |
b7449926 XL |
1708 | /// The effect of this annotation is to relate the type `T_y` of the place `y` |
1709 | /// to the user-given type `T`. The effect depends on the specified variance: | |
0531ce1d | 1710 | /// |
b7449926 XL |
1711 | /// - `Covariant` -- requires that `T_y <: T` |
1712 | /// - `Contravariant` -- requires that `T_y :> T` | |
1713 | /// - `Invariant` -- requires that `T_y == T` | |
1714 | /// - `Bivariant` -- no effect | |
04454e1e FG |
1715 | /// |
1716 | /// When executed at runtime this is a nop. | |
1717 | /// | |
1718 | /// Disallowed after drop elaboration. | |
e1599b0c | 1719 | AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), |
0531ce1d | 1720 | |
5099ac24 | 1721 | /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A |
cdc7bbd5 XL |
1722 | /// `Coverage` statement carries metadata about the coverage region, used to inject a coverage |
1723 | /// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates | |
1724 | /// executable code, to increment a counter variable at runtime, each time the code region is | |
1725 | /// executed. | |
3dfed10e XL |
1726 | Coverage(Box<Coverage>), |
1727 | ||
04454e1e FG |
1728 | /// Denotes a call to the intrinsic function `copy_nonoverlapping`. |
1729 | /// | |
1730 | /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer, | |
1731 | /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and | |
1732 | /// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of | |
1733 | /// the `src` place are copied to the continguous range of bytes beginning with the first byte | |
1734 | /// of `dest`. | |
1735 | /// | |
1736 | /// **Needs clarification**: In what order are operands computed and dereferenced? It should | |
1737 | /// probably match the order for assignment, but that is also undecided. | |
1738 | /// | |
1739 | /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved? | |
1740 | /// I vaguely remember Ralf saying somewhere that he thought it should not be. | |
6a06907d XL |
1741 | CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>), |
1742 | ||
9e0c209e SL |
1743 | /// No-op. Useful for deleting instructions without affecting statement indices. |
1744 | Nop, | |
e9174d1e SL |
1745 | } |
1746 | ||
1b1a35ee | 1747 | impl<'tcx> StatementKind<'tcx> { |
6a06907d XL |
1748 | pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> { |
1749 | match self { | |
1750 | StatementKind::Assign(x) => Some(x), | |
1751 | _ => None, | |
1752 | } | |
1753 | } | |
1754 | ||
1755 | pub fn as_assign(&self) -> Option<&(Place<'tcx>, Rvalue<'tcx>)> { | |
1b1a35ee XL |
1756 | match self { |
1757 | StatementKind::Assign(x) => Some(x), | |
1758 | _ => None, | |
1759 | } | |
1760 | } | |
1761 | } | |
1762 | ||
e1599b0c | 1763 | /// Describes what kind of retag is to be performed. |
6a06907d | 1764 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)] |
0731742a | 1765 | pub enum RetagKind { |
e1599b0c | 1766 | /// The initial retag when entering a function. |
0731742a | 1767 | FnEntry, |
e1599b0c | 1768 | /// Retag preparing for a two-phase borrow. |
0731742a | 1769 | TwoPhase, |
e1599b0c | 1770 | /// Retagging raw pointers. |
0731742a | 1771 | Raw, |
e1599b0c | 1772 | /// A "normal" retag. |
0731742a XL |
1773 | Default, |
1774 | } | |
1775 | ||
e1599b0c | 1776 | /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. |
6a06907d | 1777 | #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)] |
0bf4aa26 | 1778 | pub enum FakeReadCause { |
9fa01778 XL |
1779 | /// Inject a fake read of the borrowed input at the end of each guards |
1780 | /// code. | |
0bf4aa26 | 1781 | /// |
9fa01778 XL |
1782 | /// This should ensure that you cannot change the variant for an enum while |
1783 | /// you are in the midst of matching on it. | |
0bf4aa26 XL |
1784 | ForMatchGuard, |
1785 | ||
1786 | /// `let x: !; match x {}` doesn't generate any read of x so we need to | |
1787 | /// generate a read of x to check that it is initialized and safe. | |
cdc7bbd5 XL |
1788 | /// |
1789 | /// If a closure pattern matches a Place starting with an Upvar, then we introduce a | |
1790 | /// FakeRead for that Place outside the closure, in such a case this option would be | |
1791 | /// Some(closure_def_id). | |
1792 | /// Otherwise, the value of the optional DefId will be None. | |
1793 | ForMatchedPlace(Option<DefId>), | |
0bf4aa26 | 1794 | |
9fa01778 | 1795 | /// A fake read of the RefWithinGuard version of a bind-by-value variable |
5099ac24 | 1796 | /// in a match guard to ensure that its value hasn't change by the time |
9fa01778 XL |
1797 | /// we create the OutsideGuard version. |
1798 | ForGuardBinding, | |
1799 | ||
0bf4aa26 XL |
1800 | /// Officially, the semantics of |
1801 | /// | |
1802 | /// `let pattern = <expr>;` | |
1803 | /// | |
1804 | /// is that `<expr>` is evaluated into a temporary and then this temporary is | |
1805 | /// into the pattern. | |
1806 | /// | |
1807 | /// However, if we see the simple pattern `let var = <expr>`, we optimize this to | |
1808 | /// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable, | |
1809 | /// but in some cases it can affect the borrow checker, as in #53695. | |
1810 | /// Therefore, we insert a "fake read" here to ensure that we get | |
1811 | /// appropriate errors. | |
cdc7bbd5 XL |
1812 | /// |
1813 | /// If a closure pattern matches a Place starting with an Upvar, then we introduce a | |
1814 | /// FakeRead for that Place outside the closure, in such a case this option would be | |
1815 | /// Some(closure_def_id). | |
1816 | /// Otherwise, the value of the optional DefId will be None. | |
1817 | ForLet(Option<DefId>), | |
60c5eb7d XL |
1818 | |
1819 | /// If we have an index expression like | |
1820 | /// | |
1821 | /// (*x)[1][{ x = y; 4}] | |
1822 | /// | |
1823 | /// then the first bounds check is invalidated when we evaluate the second | |
1824 | /// index expression. Thus we create a fake borrow of `x` across the second | |
1825 | /// indexer, which will cause a borrow check error. | |
1826 | ForIndex, | |
0bf4aa26 XL |
1827 | } |
1828 | ||
e1599b0c | 1829 | impl Debug for Statement<'_> { |
0bf4aa26 | 1830 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
1831 | use self::StatementKind::*; |
1832 | match self.kind { | |
dfeec247 | 1833 | Assign(box (ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv), |
cdc7bbd5 XL |
1834 | FakeRead(box (ref cause, ref place)) => { |
1835 | write!(fmt, "FakeRead({:?}, {:?})", cause, place) | |
1836 | } | |
416331ca XL |
1837 | Retag(ref kind, ref place) => write!( |
1838 | fmt, | |
1839 | "Retag({}{:?})", | |
1840 | match kind { | |
1841 | RetagKind::FnEntry => "[fn entry] ", | |
1842 | RetagKind::TwoPhase => "[2phase] ", | |
1843 | RetagKind::Raw => "[raw] ", | |
1844 | RetagKind::Default => "", | |
1845 | }, | |
1846 | place, | |
1847 | ), | |
ff7c6d11 XL |
1848 | StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place), |
1849 | StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place), | |
416331ca XL |
1850 | SetDiscriminant { ref place, variant_index } => { |
1851 | write!(fmt, "discriminant({:?}) = {:?}", place, variant_index) | |
1852 | } | |
04454e1e | 1853 | Deinit(ref place) => write!(fmt, "Deinit({:?})", place), |
dfeec247 | 1854 | AscribeUserType(box (ref place, ref c_ty), ref variance) => { |
b7449926 | 1855 | write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) |
94b46f34 | 1856 | } |
94222f64 XL |
1857 | Coverage(box self::Coverage { ref kind, code_region: Some(ref rgn) }) => { |
1858 | write!(fmt, "Coverage::{:?} for {:?}", kind, rgn) | |
1b1a35ee | 1859 | } |
94222f64 | 1860 | Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind), |
6a06907d XL |
1861 | CopyNonOverlapping(box crate::mir::CopyNonOverlapping { |
1862 | ref src, | |
1863 | ref dst, | |
1864 | ref count, | |
1865 | }) => { | |
1866 | write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count) | |
1867 | } | |
9e0c209e | 1868 | Nop => write!(fmt, "nop"), |
e9174d1e SL |
1869 | } |
1870 | } | |
1871 | } | |
54a0048b | 1872 | |
6a06907d | 1873 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] |
3dfed10e XL |
1874 | pub struct Coverage { |
1875 | pub kind: CoverageKind, | |
29967ef6 | 1876 | pub code_region: Option<CodeRegion>, |
3dfed10e XL |
1877 | } |
1878 | ||
6a06907d XL |
1879 | #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] |
1880 | pub struct CopyNonOverlapping<'tcx> { | |
1881 | pub src: Operand<'tcx>, | |
1882 | pub dst: Operand<'tcx>, | |
1883 | /// Number of elements to copy from src to dest, not bytes. | |
1884 | pub count: Operand<'tcx>, | |
1885 | } | |
1886 | ||
e9174d1e | 1887 | /////////////////////////////////////////////////////////////////////////// |
ff7c6d11 | 1888 | // Places |
e9174d1e | 1889 | |
04454e1e FG |
1890 | /// Places roughly correspond to a "location in memory." Places in MIR are the same mathematical |
1891 | /// object as places in Rust. This of course means that what exactly they are is undecided and part | |
1892 | /// of the Rust memory model. However, they will likely contain at least the following pieces of | |
1893 | /// information in some form: | |
1894 | /// | |
1895 | /// 1. The address in memory that the place refers to. | |
1896 | /// 2. The provenance with which the place is being accessed. | |
1897 | /// 3. The type of the place and an optional variant index. See [`PlaceTy`][tcx::PlaceTy]. | |
1898 | /// 4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`. | |
1899 | /// | |
1900 | /// We'll give a description below of how all pieces of the place except for the provenance are | |
1901 | /// calculated. We cannot give a description of the provenance, because that is part of the | |
1902 | /// undecided aliasing model - we only include it here at all to acknowledge its existence. | |
1903 | /// | |
1904 | /// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has | |
1905 | /// the address of the local's allocation and the type of the local. | |
1906 | /// | |
1907 | /// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation | |
1908 | /// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation. | |
1909 | /// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under | |
1910 | /// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and | |
1911 | /// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into | |
1912 | /// the current MIR semantics in a clean way - possibly this needs some design work first. | |
1913 | /// | |
1914 | /// For places that are not locals, ie they have a non-empty list of projections, we define the | |
1915 | /// values as a function of the parent place, that is the place with its last [`ProjectionElem`] | |
1916 | /// stripped. The way this is computed of course depends on the kind of that last projection | |
1917 | /// element: | |
1918 | /// | |
1919 | /// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the | |
1920 | /// given one, and makes no other changes. A `Downcast` projection on a place with its variant | |
1921 | /// index already set is not well-formed. | |
1922 | /// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a | |
1923 | /// place referring to one of the fields of the type. The resulting address is the parent | |
1924 | /// address, plus the offset of the field. The type becomes the type of the field. If the parent | |
1925 | /// was unsized and so had metadata associated with it, then the metadata is retained if the | |
1926 | /// field is unsized and thrown out if it is sized. | |
1927 | /// | |
1928 | /// These projections are only legal for tuples, ADTs, closures, and generators. If the ADT or | |
1929 | /// generator has more than one variant, the parent place's variant index must be set, indicating | |
1930 | /// which variant is being used. If it has just one variant, the variant index may or may not be | |
1931 | /// included - the single possible variant is inferred if it is not included. | |
1932 | /// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the | |
1933 | /// place as described in the documentation for the `ProjectionElem`. The resulting address is | |
1934 | /// the parent's address plus that offset, and the type is `T`. This is only legal if the parent | |
1935 | /// place has type `[T; N]` or `[T]` (*not* `&[T]`). Since such a `T` is always sized, any | |
1936 | /// resulting metadata is thrown out. | |
1937 | /// - [`Subslice`](ProjectionElem::Subslice): This projection calculates an offset and a new | |
1938 | /// address in a similar manner as `ConstantIndex`. It is also only legal on `[T; N]` and `[T]`. | |
1939 | /// However, this yields a `Place` of type `[T]`, and additionally sets the metadata to be the | |
1940 | /// length of the subslice. | |
1941 | /// - [`Index`](ProjectionElem::Index): Like `ConstantIndex`, only legal on `[T; N]` or `[T]`. | |
1942 | /// However, `Index` additionally takes a local from which the value of the index is computed at | |
1943 | /// runtime. Computing the value of the index involves interpreting the `Local` as a | |
1944 | /// `Place { local, projection: [] }`, and then computing its value as if done via | |
1945 | /// [`Operand::Copy`]. The array/slice is then indexed with the resulting value. The local must | |
1946 | /// have type `usize`. | |
1947 | /// - [`Deref`](ProjectionElem::Deref): Derefs are the last type of projection, and the most | |
1948 | /// complicated. They are only legal on parent places that are references, pointers, or `Box`. A | |
1949 | /// `Deref` projection begins by loading a value from the parent place, as if by | |
1950 | /// [`Operand::Copy`]. It then dereferences the resulting pointer, creating a place of the | |
1951 | /// pointee's type. The resulting address is the address that was stored in the pointer. If the | |
1952 | /// pointee type is unsized, the pointer additionally stored the value of the metadata. | |
1953 | /// | |
1954 | /// Computing a place may cause UB. One possibility is that the pointer used for a `Deref` may not | |
1955 | /// be suitably aligned. Another possibility is that the place is not in bounds, meaning it does not | |
1956 | /// point to an actual allocation. | |
1957 | /// | |
1958 | /// However, if this is actually UB and when the UB kicks in is undecided. This is being discussed | |
1959 | /// in [UCG#319]. The options include that every place must obey those rules, that only some places | |
1960 | /// must obey them, or that places impose no rules of their own. | |
1961 | /// | |
1962 | /// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319 | |
1963 | /// | |
1964 | /// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken | |
1965 | /// advantage of by codegen (via `gep inbounds`). That is possibly subject to change. | |
5099ac24 | 1966 | #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)] |
416331ca | 1967 | pub struct Place<'tcx> { |
dfeec247 | 1968 | pub local: Local, |
532ac7d7 XL |
1969 | |
1970 | /// projection out of a place (access a field, deref a pointer, etc) | |
e74abb32 | 1971 | pub projection: &'tcx List<PlaceElem<'tcx>>, |
532ac7d7 XL |
1972 | } |
1973 | ||
c295e0f8 | 1974 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
6a06907d XL |
1975 | static_assert_size!(Place<'_>, 16); |
1976 | ||
60c5eb7d | 1977 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
3dfed10e | 1978 | #[derive(TyEncodable, TyDecodable, HashStable)] |
532ac7d7 | 1979 | pub enum ProjectionElem<V, T> { |
e9174d1e | 1980 | Deref, |
3b2f2976 | 1981 | Field(Field, T), |
5e7ed085 FG |
1982 | /// Index into a slice/array. |
1983 | /// | |
1984 | /// Note that this does not also dereference, and so it does not exactly correspond to slice | |
1985 | /// indexing in Rust. In other words, in the below Rust code: | |
1986 | /// | |
1987 | /// ```rust | |
1988 | /// let x = &[1, 2, 3, 4]; | |
1989 | /// let i = 2; | |
1990 | /// x[i]; | |
1991 | /// ``` | |
1992 | /// | |
1993 | /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same | |
1994 | /// thing is true of the `ConstantIndex` and `Subslice` projections below. | |
e9174d1e SL |
1995 | Index(V), |
1996 | ||
7453a54e SL |
1997 | /// These indices are generated by slice patterns. Easiest to explain |
1998 | /// by example: | |
1999 | /// | |
04454e1e | 2000 | /// ```ignore (illustrative) |
7453a54e SL |
2001 | /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, |
2002 | /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, | |
2003 | /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, | |
2004 | /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, | |
2005 | /// ``` | |
e9174d1e | 2006 | ConstantIndex { |
7453a54e | 2007 | /// index or -index (in Python terms), depending on from_end |
1b1a35ee | 2008 | offset: u64, |
60c5eb7d XL |
2009 | /// The thing being indexed must be at least this long. For arrays this |
2010 | /// is always the exact length. | |
1b1a35ee | 2011 | min_length: u64, |
60c5eb7d XL |
2012 | /// Counting backwards from end? This is always false when indexing an |
2013 | /// array. | |
7453a54e | 2014 | from_end: bool, |
e9174d1e SL |
2015 | }, |
2016 | ||
3157f602 XL |
2017 | /// These indices are generated by slice patterns. |
2018 | /// | |
60c5eb7d XL |
2019 | /// If `from_end` is true `slice[from..slice.len() - to]`. |
2020 | /// Otherwise `array[from..to]`. | |
3157f602 | 2021 | Subslice { |
1b1a35ee XL |
2022 | from: u64, |
2023 | to: u64, | |
60c5eb7d XL |
2024 | /// Whether `to` counts from the start or end of the array/slice. |
2025 | /// For `PlaceElem`s this is `true` if and only if the base is a slice. | |
2026 | /// For `ProjectionKind`, this can also be `true` for arrays. | |
2027 | from_end: bool, | |
3157f602 XL |
2028 | }, |
2029 | ||
04454e1e | 2030 | /// "Downcast" to a variant of an enum or a generator. |
532ac7d7 XL |
2031 | /// |
2032 | /// The included Symbol is the name of the variant, used for printing MIR. | |
2033 | Downcast(Option<Symbol>, VariantIdx), | |
e9174d1e SL |
2034 | } |
2035 | ||
e1599b0c XL |
2036 | impl<V, T> ProjectionElem<V, T> { |
2037 | /// Returns `true` if the target of this projection may refer to a different region of memory | |
2038 | /// than the base. | |
2039 | fn is_indirect(&self) -> bool { | |
2040 | match self { | |
2041 | Self::Deref => true, | |
2042 | ||
dfeec247 | 2043 | Self::Field(_, _) |
e1599b0c XL |
2044 | | Self::Index(_) |
2045 | | Self::ConstantIndex { .. } | |
2046 | | Self::Subslice { .. } | |
dfeec247 | 2047 | | Self::Downcast(_, _) => false, |
e1599b0c XL |
2048 | } |
2049 | } | |
a2a8927a XL |
2050 | |
2051 | /// Returns `true` if this is a `Downcast` projection with the given `VariantIdx`. | |
2052 | pub fn is_downcast_to(&self, v: VariantIdx) -> bool { | |
2053 | matches!(*self, Self::Downcast(_, x) if x == v) | |
2054 | } | |
2055 | ||
2056 | /// Returns `true` if this is a `Field` projection with the given index. | |
2057 | pub fn is_field_to(&self, f: Field) -> bool { | |
2058 | matches!(*self, Self::Field(x, _) if x == f) | |
2059 | } | |
e1599b0c XL |
2060 | } |
2061 | ||
ff7c6d11 | 2062 | /// Alias for projections as they appear in places, where the base is a place |
ea8adc8c | 2063 | /// and the index is a local. |
532ac7d7 | 2064 | pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; |
e9174d1e | 2065 | |
5e7ed085 FG |
2066 | // This type is fairly frequently used, so we shouldn't unintentionally increase |
2067 | // its size. | |
6a06907d | 2068 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
1b1a35ee | 2069 | static_assert_size!(PlaceElem<'_>, 24); |
a1dfa0c6 | 2070 | |
0bf4aa26 XL |
2071 | /// Alias for projections as they appear in `UserTypeProjection`, where we |
2072 | /// need neither the `V` parameter for `Index` nor the `T` for `Field`. | |
532ac7d7 | 2073 | pub type ProjectionKind = ProjectionElem<(), ()>; |
0bf4aa26 | 2074 | |
e74abb32 | 2075 | rustc_index::newtype_index! { |
5e7ed085 FG |
2076 | /// A [newtype'd][wrapper] index type in the MIR [control-flow graph][CFG] |
2077 | /// | |
2078 | /// A field (e.g., `f` in `_1.f`) is one variant of [`ProjectionElem`]. Conceptually, | |
2079 | /// rustc can identify that a field projection refers to either two different regions of memory | |
2080 | /// or the same one between the base and the 'projection element'. | |
2081 | /// Read more about projections in the [rustc-dev-guide][mir-datatypes] | |
2082 | /// | |
2083 | /// [wrapper]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html#newtype | |
2084 | /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg | |
2085 | /// [mir-datatypes]: https://rustc-dev-guide.rust-lang.org/mir/index.html#mir-data-types | |
b7449926 | 2086 | pub struct Field { |
532ac7d7 | 2087 | derive [HashStable] |
b7449926 XL |
2088 | DEBUG_FORMAT = "field[{}]" |
2089 | } | |
2090 | } | |
e9174d1e | 2091 | |
04454e1e | 2092 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
74b04a01 XL |
2093 | pub struct PlaceRef<'tcx> { |
2094 | pub local: Local, | |
2095 | pub projection: &'tcx [PlaceElem<'tcx>], | |
416331ca XL |
2096 | } |
2097 | ||
04454e1e FG |
2098 | // Once we stop implementing `Ord` for `DefId`, |
2099 | // this impl will be unnecessary. Until then, we'll | |
2100 | // leave this impl in place to prevent re-adding a | |
2101 | // dependnecy on the `Ord` impl for `DefId` | |
2102 | impl<'tcx> !PartialOrd for PlaceRef<'tcx> {} | |
2103 | ||
ff7c6d11 | 2104 | impl<'tcx> Place<'tcx> { |
e74abb32 | 2105 | // FIXME change this to a const fn by also making List::empty a const fn. |
e1599b0c | 2106 | pub fn return_place() -> Place<'tcx> { |
dfeec247 | 2107 | Place { local: RETURN_PLACE, projection: List::empty() } |
e9174d1e | 2108 | } |
0bf4aa26 | 2109 | |
e1599b0c XL |
2110 | /// Returns `true` if this `Place` contains a `Deref` projection. |
2111 | /// | |
2112 | /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the | |
2113 | /// same region of memory as its base. | |
2114 | pub fn is_indirect(&self) -> bool { | |
2115 | self.projection.iter().any(|elem| elem.is_indirect()) | |
2116 | } | |
2117 | ||
9fa01778 | 2118 | /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or |
0bf4aa26 | 2119 | /// a single deref of a local. |
5869c6ff | 2120 | #[inline(always)] |
dc9dc135 | 2121 | pub fn local_or_deref_local(&self) -> Option<Local> { |
5869c6ff | 2122 | self.as_ref().local_or_deref_local() |
0bf4aa26 XL |
2123 | } |
2124 | ||
e1599b0c XL |
2125 | /// If this place represents a local variable like `_X` with no |
2126 | /// projections, return `Some(_X)`. | |
5869c6ff | 2127 | #[inline(always)] |
e1599b0c | 2128 | pub fn as_local(&self) -> Option<Local> { |
e74abb32 | 2129 | self.as_ref().as_local() |
416331ca XL |
2130 | } |
2131 | ||
6a06907d | 2132 | #[inline] |
74b04a01 XL |
2133 | pub fn as_ref(&self) -> PlaceRef<'tcx> { |
2134 | PlaceRef { local: self.local, projection: &self.projection } | |
0bf4aa26 | 2135 | } |
fc512014 XL |
2136 | |
2137 | /// Iterate over the projections in evaluation order, i.e., the first element is the base with | |
2138 | /// its projection and then subsequently more projections are added. | |
2139 | /// As a concrete example, given the place a.b.c, this would yield: | |
2140 | /// - (a, .b) | |
2141 | /// - (a.b, .c) | |
5869c6ff | 2142 | /// |
fc512014 | 2143 | /// Given a place without projections, the iterator is empty. |
6a06907d | 2144 | #[inline] |
fc512014 XL |
2145 | pub fn iter_projections( |
2146 | self, | |
2147 | ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator { | |
923072b8 | 2148 | self.as_ref().iter_projections() |
fc512014 | 2149 | } |
5e7ed085 FG |
2150 | |
2151 | /// Generates a new place by appending `more_projections` to the existing ones | |
2152 | /// and interning the result. | |
2153 | pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self { | |
2154 | if more_projections.is_empty() { | |
2155 | return self; | |
2156 | } | |
2157 | ||
2158 | let mut v: Vec<PlaceElem<'tcx>>; | |
2159 | ||
2160 | let new_projections = if self.projection.is_empty() { | |
2161 | more_projections | |
2162 | } else { | |
2163 | v = Vec::with_capacity(self.projection.len() + more_projections.len()); | |
2164 | v.extend(self.projection); | |
2165 | v.extend(more_projections); | |
2166 | &v | |
2167 | }; | |
2168 | ||
2169 | Place { local: self.local, projection: tcx.intern_place_elems(new_projections) } | |
2170 | } | |
e9174d1e SL |
2171 | } |
2172 | ||
dc9dc135 XL |
2173 | impl From<Local> for Place<'_> { |
2174 | fn from(local: Local) -> Self { | |
dfeec247 | 2175 | Place { local, projection: List::empty() } |
dc9dc135 XL |
2176 | } |
2177 | } | |
2178 | ||
74b04a01 | 2179 | impl<'tcx> PlaceRef<'tcx> { |
416331ca XL |
2180 | /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or |
2181 | /// a single deref of a local. | |
416331ca | 2182 | pub fn local_or_deref_local(&self) -> Option<Local> { |
74b04a01 | 2183 | match *self { |
dfeec247 | 2184 | PlaceRef { local, projection: [] } |
74b04a01 | 2185 | | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), |
416331ca XL |
2186 | _ => None, |
2187 | } | |
2188 | } | |
e74abb32 XL |
2189 | |
2190 | /// If this place represents a local variable like `_X` with no | |
2191 | /// projections, return `Some(_X)`. | |
17df50a5 | 2192 | #[inline] |
e74abb32 | 2193 | pub fn as_local(&self) -> Option<Local> { |
74b04a01 XL |
2194 | match *self { |
2195 | PlaceRef { local, projection: [] } => Some(local), | |
e74abb32 XL |
2196 | _ => None, |
2197 | } | |
2198 | } | |
5869c6ff | 2199 | |
17df50a5 | 2200 | #[inline] |
5869c6ff XL |
2201 | pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> { |
2202 | if let &[ref proj_base @ .., elem] = self.projection { | |
2203 | Some((PlaceRef { local: self.local, projection: proj_base }, elem)) | |
2204 | } else { | |
2205 | None | |
2206 | } | |
2207 | } | |
923072b8 FG |
2208 | |
2209 | /// Iterate over the projections in evaluation order, i.e., the first element is the base with | |
2210 | /// its projection and then subsequently more projections are added. | |
2211 | /// As a concrete example, given the place a.b.c, this would yield: | |
2212 | /// - (a, .b) | |
2213 | /// - (a.b, .c) | |
2214 | /// | |
2215 | /// Given a place without projections, the iterator is empty. | |
2216 | #[inline] | |
2217 | pub fn iter_projections( | |
2218 | self, | |
2219 | ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator { | |
2220 | self.projection.iter().enumerate().map(move |(i, proj)| { | |
2221 | let base = PlaceRef { local: self.local, projection: &self.projection[..i] }; | |
2222 | (base, *proj) | |
2223 | }) | |
2224 | } | |
416331ca XL |
2225 | } |
2226 | ||
e1599b0c | 2227 | impl Debug for Place<'_> { |
0bf4aa26 | 2228 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e1599b0c XL |
2229 | for elem in self.projection.iter().rev() { |
2230 | match elem { | |
2231 | ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { | |
2232 | write!(fmt, "(").unwrap(); | |
2233 | } | |
2234 | ProjectionElem::Deref => { | |
2235 | write!(fmt, "(*").unwrap(); | |
94b46f34 | 2236 | } |
e1599b0c XL |
2237 | ProjectionElem::Index(_) |
2238 | | ProjectionElem::ConstantIndex { .. } | |
2239 | | ProjectionElem::Subslice { .. } => {} | |
48663c56 | 2240 | } |
e1599b0c | 2241 | } |
48663c56 | 2242 | |
dfeec247 | 2243 | write!(fmt, "{:?}", self.local)?; |
48663c56 | 2244 | |
e1599b0c XL |
2245 | for elem in self.projection.iter() { |
2246 | match elem { | |
2247 | ProjectionElem::Downcast(Some(name), _index) => { | |
2248 | write!(fmt, " as {})", name)?; | |
2249 | } | |
2250 | ProjectionElem::Downcast(None, index) => { | |
2251 | write!(fmt, " as variant#{:?})", index)?; | |
2252 | } | |
2253 | ProjectionElem::Deref => { | |
2254 | write!(fmt, ")")?; | |
2255 | } | |
2256 | ProjectionElem::Field(field, ty) => { | |
2257 | write!(fmt, ".{:?}: {:?})", field.index(), ty)?; | |
2258 | } | |
2259 | ProjectionElem::Index(ref index) => { | |
2260 | write!(fmt, "[{:?}]", index)?; | |
2261 | } | |
2262 | ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { | |
2263 | write!(fmt, "[{:?} of {:?}]", offset, min_length)?; | |
2264 | } | |
2265 | ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { | |
2266 | write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; | |
2267 | } | |
f9f354fc | 2268 | ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => { |
e1599b0c XL |
2269 | write!(fmt, "[{:?}:]", from)?; |
2270 | } | |
f9f354fc | 2271 | ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => { |
e1599b0c XL |
2272 | write!(fmt, "[:-{:?}]", to)?; |
2273 | } | |
60c5eb7d | 2274 | ProjectionElem::Subslice { from, to, from_end: true } => { |
e1599b0c | 2275 | write!(fmt, "[{:?}:-{:?}]", from, to)?; |
94b46f34 | 2276 | } |
60c5eb7d XL |
2277 | ProjectionElem::Subslice { from, to, from_end: false } => { |
2278 | write!(fmt, "[{:?}..{:?}]", from, to)?; | |
2279 | } | |
48663c56 | 2280 | } |
e1599b0c | 2281 | } |
48663c56 | 2282 | |
e1599b0c | 2283 | Ok(()) |
e9174d1e SL |
2284 | } |
2285 | } | |
2286 | ||
54a0048b SL |
2287 | /////////////////////////////////////////////////////////////////////////// |
2288 | // Scopes | |
2289 | ||
e74abb32 | 2290 | rustc_index::newtype_index! { |
b7449926 | 2291 | pub struct SourceScope { |
532ac7d7 | 2292 | derive [HashStable] |
abe05a73 | 2293 | DEBUG_FORMAT = "scope[{}]", |
94b46f34 | 2294 | const OUTERMOST_SOURCE_SCOPE = 0, |
b7449926 XL |
2295 | } |
2296 | } | |
54a0048b | 2297 | |
cdc7bbd5 XL |
2298 | impl SourceScope { |
2299 | /// Finds the original HirId this MIR item came from. | |
2300 | /// This is necessary after MIR optimizations, as otherwise we get a HirId | |
2301 | /// from the function that was inlined instead of the function call site. | |
a2a8927a | 2302 | pub fn lint_root<'tcx>( |
cdc7bbd5 XL |
2303 | self, |
2304 | source_scopes: &IndexVec<SourceScope, SourceScopeData<'tcx>>, | |
2305 | ) -> Option<HirId> { | |
2306 | let mut data = &source_scopes[self]; | |
2307 | // FIXME(oli-obk): we should be able to just walk the `inlined_parent_scope`, but it | |
2308 | // does not work as I thought it would. Needs more investigation and documentation. | |
2309 | while data.inlined.is_some() { | |
2310 | trace!(?data); | |
2311 | data = &source_scopes[data.parent_scope.unwrap()]; | |
2312 | } | |
2313 | trace!(?data); | |
2314 | match &data.local_data { | |
2315 | ClearCrossCrate::Set(data) => Some(data.lint_root), | |
2316 | ClearCrossCrate::Clear => None, | |
2317 | } | |
2318 | } | |
2319 | } | |
2320 | ||
29967ef6 XL |
2321 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
2322 | pub struct SourceScopeData<'tcx> { | |
a7813a04 | 2323 | pub span: Span, |
94b46f34 | 2324 | pub parent_scope: Option<SourceScope>, |
60c5eb7d | 2325 | |
29967ef6 XL |
2326 | /// Whether this scope is the root of a scope tree of another body, |
2327 | /// inlined into this body by the MIR inliner. | |
2328 | /// `ty::Instance` is the callee, and the `Span` is the call site. | |
2329 | pub inlined: Option<(ty::Instance<'tcx>, Span)>, | |
2330 | ||
2331 | /// Nearest (transitive) parent scope (if any) which is inlined. | |
2332 | /// This is an optimization over walking up `parent_scope` | |
2333 | /// until a scope with `inlined: Some(...)` is found. | |
2334 | pub inlined_parent_scope: Option<SourceScope>, | |
2335 | ||
60c5eb7d XL |
2336 | /// Crate-local information for this source scope, that can't (and |
2337 | /// needn't) be tracked across crates. | |
2338 | pub local_data: ClearCrossCrate<SourceScopeLocalData>, | |
94b46f34 XL |
2339 | } |
2340 | ||
3dfed10e | 2341 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] |
94b46f34 | 2342 | pub struct SourceScopeLocalData { |
e1599b0c | 2343 | /// An `HirId` with lint levels equivalent to this scope's lint levels. |
532ac7d7 | 2344 | pub lint_root: hir::HirId, |
94b46f34 XL |
2345 | /// The unsafe block that contains this node. |
2346 | pub safety: Safety, | |
54a0048b SL |
2347 | } |
2348 | ||
e9174d1e SL |
2349 | /////////////////////////////////////////////////////////////////////////// |
2350 | // Operands | |
54a0048b | 2351 | |
04454e1e FG |
2352 | /// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of |
2353 | /// the memory model. One proposal for a definition of values can be found [on UCG][value-def]. | |
2354 | /// | |
2355 | /// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md | |
2356 | /// | |
2357 | /// The most common way to create values is via loading a place. Loading a place is an operation | |
2358 | /// which reads the memory of the place and converts it to a value. This is a fundamentally *typed* | |
2359 | /// operation. The nature of the value produced depends on the type of the conversion. Furthermore, | |
2360 | /// there may be other effects: if the type has a validity constraint loading the place might be UB | |
2361 | /// if the validity constraint is not met. | |
2362 | /// | |
2363 | /// **Needs clarification:** Ralf proposes that loading a place not have side-effects. | |
2364 | /// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this | |
2365 | /// something we can even decide without knowing more about Rust's memory model? | |
2366 | /// | |
2367 | /// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri | |
2368 | /// currently implements it, but it seems like this may be something to check against in the | |
2369 | /// validator. | |
5099ac24 | 2370 | #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] |
b039eaaf | 2371 | pub enum Operand<'tcx> { |
04454e1e | 2372 | /// Creates a value by loading the given place. |
ff7c6d11 | 2373 | /// |
04454e1e FG |
2374 | /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there |
2375 | /// is no such requirement. | |
ff7c6d11 | 2376 | Copy(Place<'tcx>), |
b7449926 | 2377 | |
04454e1e FG |
2378 | /// Creates a value by performing loading the place, just like the `Copy` operand. |
2379 | /// | |
2380 | /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide | |
2381 | /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this | |
2382 | /// place without first re-initializing it. | |
ff7c6d11 | 2383 | /// |
04454e1e | 2384 | /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188 |
ff7c6d11 | 2385 | Move(Place<'tcx>), |
b7449926 | 2386 | |
04454e1e | 2387 | /// Constants are already semantically values, and remain unchanged. |
cc61c64b | 2388 | Constant(Box<Constant<'tcx>>), |
e9174d1e SL |
2389 | } |
2390 | ||
c295e0f8 | 2391 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
6a06907d XL |
2392 | static_assert_size!(Operand<'_>, 24); |
2393 | ||
b039eaaf | 2394 | impl<'tcx> Debug for Operand<'tcx> { |
0bf4aa26 | 2395 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
2396 | use self::Operand::*; |
2397 | match *self { | |
2398 | Constant(ref a) => write!(fmt, "{:?}", a), | |
ff7c6d11 XL |
2399 | Copy(ref place) => write!(fmt, "{:?}", place), |
2400 | Move(ref place) => write!(fmt, "move {:?}", place), | |
e9174d1e SL |
2401 | } |
2402 | } | |
2403 | } | |
2404 | ||
cc61c64b | 2405 | impl<'tcx> Operand<'tcx> { |
b7449926 | 2406 | /// Convenience helper to make a constant that refers to the fn |
9fa01778 | 2407 | /// with given `DefId` and substs. Since this is used to synthesize |
b7449926 | 2408 | /// MIR, assumes `user_ty` is None. |
dc9dc135 XL |
2409 | pub fn function_handle( |
2410 | tcx: TyCtxt<'tcx>, | |
cc61c64b | 2411 | def_id: DefId, |
532ac7d7 | 2412 | substs: SubstsRef<'tcx>, |
cc61c64b XL |
2413 | span: Span, |
2414 | ) -> Self { | |
04454e1e | 2415 | let ty = tcx.bound_type_of(def_id).subst(tcx, substs); |
94222f64 | 2416 | Operand::Constant(Box::new(Constant { |
041b39d2 | 2417 | span, |
b7449926 | 2418 | user_ty: None, |
923072b8 | 2419 | literal: ConstantKind::Val(ConstValue::zst(), ty), |
94222f64 | 2420 | })) |
cc61c64b XL |
2421 | } |
2422 | ||
1b1a35ee XL |
2423 | pub fn is_move(&self) -> bool { |
2424 | matches!(self, Operand::Move(..)) | |
2425 | } | |
2426 | ||
f035d41b XL |
2427 | /// Convenience helper to make a literal-like constant from a given scalar value. |
2428 | /// Since this is used to synthesize MIR, assumes `user_ty` is None. | |
2429 | pub fn const_from_scalar( | |
2430 | tcx: TyCtxt<'tcx>, | |
2431 | ty: Ty<'tcx>, | |
2432 | val: Scalar, | |
2433 | span: Span, | |
2434 | ) -> Operand<'tcx> { | |
2435 | debug_assert!({ | |
2436 | let param_env_and_ty = ty::ParamEnv::empty().and(ty); | |
2437 | let type_size = tcx | |
2438 | .layout_of(param_env_and_ty) | |
2439 | .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) | |
2440 | .size; | |
29967ef6 XL |
2441 | let scalar_size = match val { |
2442 | Scalar::Int(int) => int.size(), | |
f035d41b | 2443 | _ => panic!("Invalid scalar type {:?}", val), |
29967ef6 | 2444 | }; |
f035d41b XL |
2445 | scalar_size == type_size |
2446 | }); | |
94222f64 | 2447 | Operand::Constant(Box::new(Constant { |
f035d41b XL |
2448 | span, |
2449 | user_ty: None, | |
136023e0 | 2450 | literal: ConstantKind::Val(ConstValue::Scalar(val), ty), |
94222f64 | 2451 | })) |
f035d41b XL |
2452 | } |
2453 | ||
ff7c6d11 XL |
2454 | pub fn to_copy(&self) -> Self { |
2455 | match *self { | |
2456 | Operand::Copy(_) | Operand::Constant(_) => self.clone(), | |
dfeec247 | 2457 | Operand::Move(place) => Operand::Copy(place), |
ff7c6d11 XL |
2458 | } |
2459 | } | |
74b04a01 XL |
2460 | |
2461 | /// Returns the `Place` that is the target of this `Operand`, or `None` if this `Operand` is a | |
2462 | /// constant. | |
ba9703b0 | 2463 | pub fn place(&self) -> Option<Place<'tcx>> { |
74b04a01 | 2464 | match self { |
ba9703b0 | 2465 | Operand::Copy(place) | Operand::Move(place) => Some(*place), |
74b04a01 XL |
2466 | Operand::Constant(_) => None, |
2467 | } | |
2468 | } | |
1b1a35ee XL |
2469 | |
2470 | /// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a | |
2471 | /// place. | |
2472 | pub fn constant(&self) -> Option<&Constant<'tcx>> { | |
2473 | match self { | |
2474 | Operand::Constant(x) => Some(&**x), | |
2475 | Operand::Copy(_) | Operand::Move(_) => None, | |
2476 | } | |
2477 | } | |
5e7ed085 FG |
2478 | |
2479 | /// Gets the `ty::FnDef` from an operand if it's a constant function item. | |
2480 | /// | |
2481 | /// While this is unlikely in general, it's the normal case of what you'll | |
2482 | /// find as the `func` in a [`TerminatorKind::Call`]. | |
2483 | pub fn const_fn_def(&self) -> Option<(DefId, SubstsRef<'tcx>)> { | |
2484 | let const_ty = self.constant()?.literal.ty(); | |
2485 | if let ty::FnDef(def_id, substs) = *const_ty.kind() { Some((def_id, substs)) } else { None } | |
2486 | } | |
cc61c64b XL |
2487 | } |
2488 | ||
e9174d1e | 2489 | /////////////////////////////////////////////////////////////////////////// |
7453a54e | 2490 | /// Rvalues |
e9174d1e | 2491 | |
6a06907d | 2492 | #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] |
5e7ed085 FG |
2493 | /// The various kinds of rvalues that can appear in MIR. |
2494 | /// | |
04454e1e FG |
2495 | /// Not all of these are allowed at every [`MirPhase`] - when this is the case, it's stated below. |
2496 | /// | |
2497 | /// Computing any rvalue begins by evaluating the places and operands in some order (**Needs | |
2498 | /// clarification**: Which order?). These are then used to produce a "value" - the same kind of | |
2499 | /// value that an [`Operand`] produces. | |
b039eaaf | 2500 | pub enum Rvalue<'tcx> { |
04454e1e | 2501 | /// Yields the operand unchanged |
b039eaaf | 2502 | Use(Operand<'tcx>), |
e9174d1e | 2503 | |
04454e1e FG |
2504 | /// Creates an array where each element is the value of the operand. |
2505 | /// | |
2506 | /// This is the cause of a bug in the case where the repetition count is zero because the value | |
2507 | /// is not dropped, see [#74836]. | |
2508 | /// | |
2509 | /// Corresponds to source code like `[x; 32]`. | |
2510 | /// | |
2511 | /// [#74836]: https://github.com/rust-lang/rust/issues/74836 | |
5099ac24 | 2512 | Repeat(Operand<'tcx>, ty::Const<'tcx>), |
e9174d1e | 2513 | |
04454e1e FG |
2514 | /// Creates a reference of the indicated kind to the place. |
2515 | /// | |
2516 | /// There is not much to document here, because besides the obvious parts the semantics of this | |
2517 | /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing | |
2518 | /// exactly what the behavior of this operation should be. | |
2519 | /// | |
2520 | /// `Shallow` borrows are disallowed after drop lowering. | |
ff7c6d11 | 2521 | Ref(Region<'tcx>, BorrowKind, Place<'tcx>), |
e9174d1e | 2522 | |
04454e1e FG |
2523 | /// Creates a pointer/reference to the given thread local. |
2524 | /// | |
2525 | /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a | |
2526 | /// `*const T`, and if neither of those apply a `&T`. | |
2527 | /// | |
2528 | /// **Note:** This is a runtime operation that actually executes code and is in this sense more | |
2529 | /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to | |
2530 | /// SIGILL for some reason that I (JakobDegen) never got a chance to look into. | |
2531 | /// | |
2532 | /// **Needs clarification**: Are there weird additional semantics here related to the runtime | |
2533 | /// nature of this operation? | |
f9f354fc XL |
2534 | ThreadLocalRef(DefId), |
2535 | ||
04454e1e FG |
2536 | /// Creates a pointer with the indicated mutability to the place. |
2537 | /// | |
2538 | /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like | |
2539 | /// `&raw v` or `addr_of!(v)`. | |
2540 | /// | |
2541 | /// Like with references, the semantics of this operation are heavily dependent on the aliasing | |
2542 | /// model. | |
dfeec247 XL |
2543 | AddressOf(Mutability, Place<'tcx>), |
2544 | ||
04454e1e FG |
2545 | /// Yields the length of the place, as a `usize`. |
2546 | /// | |
2547 | /// If the type of the place is an array, this is the array length. For slices (`[T]`, not | |
2548 | /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is | |
2549 | /// ill-formed for places of other types. | |
ff7c6d11 | 2550 | Len(Place<'tcx>), |
e9174d1e | 2551 | |
04454e1e FG |
2552 | /// Performs essentially all of the casts that can be performed via `as`. |
2553 | /// | |
2554 | /// This allows for casts from/to a variety of types. | |
2555 | /// | |
2556 | /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why | |
2557 | /// `ArrayToPointer` and `MutToConstPointer` are special. | |
b039eaaf | 2558 | Cast(CastKind, Operand<'tcx>, Ty<'tcx>), |
e9174d1e | 2559 | |
04454e1e FG |
2560 | /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second |
2561 | /// parameter may be a `usize` as well. | |
2562 | /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, | |
2563 | /// raw pointers, or function pointers and return a `bool`. The types of the operands must be | |
2564 | /// matching, up to the usual caveat of the lifetimes in function pointers. | |
2565 | /// * Left and right shift operations accept signed or unsigned integers not necessarily of the | |
2566 | /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is | |
2567 | /// truncated as needed. | |
2568 | /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching | |
2569 | /// types and return a value of that type. | |
2570 | /// * The remaining operations accept signed integers, unsigned integers, or floats with | |
2571 | /// matching types and return a value of that type. | |
6a06907d | 2572 | BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), |
04454e1e FG |
2573 | |
2574 | /// Same as `BinaryOp`, but yields `(T, bool)` instead of `T`. In addition to performing the | |
2575 | /// same computation as the matching `BinaryOp`, checks if the infinite precison result would be | |
2576 | /// unequal to the actual result and sets the `bool` if this is the case. | |
2577 | /// | |
2578 | /// This only supports addition, subtraction, multiplication, and shift operations on integers. | |
6a06907d | 2579 | CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), |
e9174d1e | 2580 | |
04454e1e | 2581 | /// Computes a value as described by the operation. |
7cac9316 | 2582 | NullaryOp(NullOp, Ty<'tcx>), |
04454e1e FG |
2583 | |
2584 | /// Exactly like `BinaryOp`, but less operands. | |
2585 | /// | |
2586 | /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; | |
2587 | /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds | |
2588 | /// return a value with the same type as their operand. | |
b039eaaf | 2589 | UnaryOp(UnOp, Operand<'tcx>), |
e9174d1e | 2590 | |
04454e1e FG |
2591 | /// Computes the discriminant of the place, returning it as an integer of type |
2592 | /// [`discriminant_ty`]. Returns zero for types without discriminant. | |
8bb4bdeb | 2593 | /// |
04454e1e FG |
2594 | /// The validity requirements for the underlying value are undecided for this rvalue, see |
2595 | /// [#91095]. Note too that the value of the discriminant is not the same thing as the | |
2596 | /// variant index; use [`discriminant_for_variant`] to convert. | |
2597 | /// | |
2598 | /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty | |
2599 | /// [#91095]: https://github.com/rust-lang/rust/issues/91095 | |
2600 | /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant | |
ff7c6d11 | 2601 | Discriminant(Place<'tcx>), |
8bb4bdeb | 2602 | |
04454e1e FG |
2603 | /// Creates an aggregate value, like a tuple or struct. |
2604 | /// | |
2605 | /// This is needed because dataflow analysis needs to distinguish | |
2606 | /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo` | |
2607 | /// has a destructor. | |
2608 | /// | |
2609 | /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After | |
2610 | /// generator lowering, `Generator` aggregate kinds are disallowed too. | |
cc61c64b | 2611 | Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), |
c295e0f8 XL |
2612 | |
2613 | /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. | |
2614 | /// | |
04454e1e FG |
2615 | /// This is different from a normal transmute because dataflow analysis will treat the box as |
2616 | /// initialized but its content as uninitialized. Like other pointer casts, this in general | |
2617 | /// affects alias analysis. | |
c295e0f8 | 2618 | ShallowInitBox(Operand<'tcx>, Ty<'tcx>), |
e9174d1e SL |
2619 | } |
2620 | ||
c295e0f8 | 2621 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
6a06907d XL |
2622 | static_assert_size!(Rvalue<'_>, 40); |
2623 | ||
923072b8 FG |
2624 | impl<'tcx> Rvalue<'tcx> { |
2625 | /// Returns true if rvalue can be safely removed when the result is unused. | |
2626 | #[inline] | |
2627 | pub fn is_safe_to_remove(&self) -> bool { | |
2628 | match self { | |
2629 | // Pointer to int casts may be side-effects due to exposing the provenance. | |
2630 | // While the model is undecided, we should be conservative. See | |
2631 | // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html> | |
2632 | Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, | |
2633 | ||
2634 | Rvalue::Use(_) | |
2635 | | Rvalue::Repeat(_, _) | |
2636 | | Rvalue::Ref(_, _, _) | |
2637 | | Rvalue::ThreadLocalRef(_) | |
2638 | | Rvalue::AddressOf(_, _) | |
2639 | | Rvalue::Len(_) | |
2640 | | Rvalue::Cast( | |
2641 | CastKind::Misc | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress, | |
2642 | _, | |
2643 | _, | |
2644 | ) | |
2645 | | Rvalue::BinaryOp(_, _) | |
2646 | | Rvalue::CheckedBinaryOp(_, _) | |
2647 | | Rvalue::NullaryOp(_, _) | |
2648 | | Rvalue::UnaryOp(_, _) | |
2649 | | Rvalue::Discriminant(_) | |
2650 | | Rvalue::Aggregate(_, _) | |
2651 | | Rvalue::ShallowInitBox(_, _) => true, | |
2652 | } | |
2653 | } | |
2654 | } | |
2655 | ||
6a06907d | 2656 | #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] |
e9174d1e | 2657 | pub enum CastKind { |
923072b8 FG |
2658 | /// An exposing pointer to address cast. A cast between a pointer and an integer type, or |
2659 | /// between a function pointer and an integer type. | |
2660 | /// See the docs on `expose_addr` for more details. | |
2661 | PointerExposeAddress, | |
2662 | /// An address-to-pointer cast that picks up an exposed provenance. | |
2663 | /// See the docs on `from_exposed_addr` for more details. | |
2664 | PointerFromExposedAddress, | |
2665 | /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are | |
2666 | /// translated into `&raw mut/const *r`, i.e., they are not actually casts. | |
48663c56 | 2667 | Pointer(PointerCast), |
923072b8 FG |
2668 | /// Remaining unclassified casts. |
2669 | Misc, | |
e9174d1e SL |
2670 | } |
2671 | ||
6a06907d | 2672 | #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] |
b039eaaf | 2673 | pub enum AggregateKind<'tcx> { |
8bb4bdeb XL |
2674 | /// The type is of the element |
2675 | Array(Ty<'tcx>), | |
e9174d1e | 2676 | Tuple, |
ff7c6d11 | 2677 | |
2c00a5a8 XL |
2678 | /// The second field is the variant index. It's equal to 0 for struct |
2679 | /// and union expressions. The fourth field is | |
ff7c6d11 | 2680 | /// active field number and is present only for union expressions |
0731742a | 2681 | /// -- e.g., for a union expression `SomeUnion { c: .. }`, the |
ff7c6d11 | 2682 | /// active field index would identity the field `c` |
a2a8927a | 2683 | Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), |
ff7c6d11 | 2684 | |
e74abb32 | 2685 | Closure(DefId, SubstsRef<'tcx>), |
60c5eb7d | 2686 | Generator(DefId, SubstsRef<'tcx>, hir::Movability), |
e9174d1e SL |
2687 | } |
2688 | ||
c295e0f8 | 2689 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
6a06907d XL |
2690 | static_assert_size!(AggregateKind<'_>, 48); |
2691 | ||
2692 | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, TyEncodable, TyDecodable, Hash, HashStable)] | |
e9174d1e SL |
2693 | pub enum BinOp { |
2694 | /// The `+` operator (addition) | |
2695 | Add, | |
2696 | /// The `-` operator (subtraction) | |
2697 | Sub, | |
2698 | /// The `*` operator (multiplication) | |
2699 | Mul, | |
2700 | /// The `/` operator (division) | |
3c0e092e | 2701 | /// |
5099ac24 FG |
2702 | /// Division by zero is UB, because the compiler should have inserted checks |
2703 | /// prior to this. | |
e9174d1e SL |
2704 | Div, |
2705 | /// The `%` operator (modulus) | |
3c0e092e | 2706 | /// |
5099ac24 FG |
2707 | /// Using zero as the modulus (second operand) is UB, because the compiler |
2708 | /// should have inserted checks prior to this. | |
e9174d1e SL |
2709 | Rem, |
2710 | /// The `^` operator (bitwise xor) | |
2711 | BitXor, | |
2712 | /// The `&` operator (bitwise and) | |
2713 | BitAnd, | |
2714 | /// The `|` operator (bitwise or) | |
2715 | BitOr, | |
2716 | /// The `<<` operator (shift left) | |
3c0e092e XL |
2717 | /// |
2718 | /// The offset is truncated to the size of the first operand before shifting. | |
e9174d1e SL |
2719 | Shl, |
2720 | /// The `>>` operator (shift right) | |
3c0e092e XL |
2721 | /// |
2722 | /// The offset is truncated to the size of the first operand before shifting. | |
e9174d1e SL |
2723 | Shr, |
2724 | /// The `==` operator (equality) | |
2725 | Eq, | |
2726 | /// The `<` operator (less than) | |
2727 | Lt, | |
2728 | /// The `<=` operator (less than or equal to) | |
2729 | Le, | |
2730 | /// The `!=` operator (not equal to) | |
2731 | Ne, | |
2732 | /// The `>=` operator (greater than or equal to) | |
2733 | Ge, | |
2734 | /// The `>` operator (greater than) | |
2735 | Gt, | |
7cac9316 XL |
2736 | /// The `ptr.offset` operator |
2737 | Offset, | |
e9174d1e SL |
2738 | } |
2739 | ||
3157f602 XL |
2740 | impl BinOp { |
2741 | pub fn is_checkable(self) -> bool { | |
2742 | use self::BinOp::*; | |
29967ef6 | 2743 | matches!(self, Add | Sub | Mul | Shl | Shr) |
3157f602 XL |
2744 | } |
2745 | } | |
2746 | ||
6a06907d | 2747 | #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] |
7cac9316 | 2748 | pub enum NullOp { |
9fa01778 | 2749 | /// Returns the size of a value of that type |
7cac9316 | 2750 | SizeOf, |
c295e0f8 XL |
2751 | /// Returns the minimum alignment of a type |
2752 | AlignOf, | |
7cac9316 XL |
2753 | } |
2754 | ||
6a06907d | 2755 | #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] |
e9174d1e SL |
2756 | pub enum UnOp { |
2757 | /// The `!` operator for logical inversion | |
2758 | Not, | |
2759 | /// The `-` operator for negation | |
b039eaaf | 2760 | Neg, |
e9174d1e SL |
2761 | } |
2762 | ||
b039eaaf | 2763 | impl<'tcx> Debug for Rvalue<'tcx> { |
0bf4aa26 | 2764 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
2765 | use self::Rvalue::*; |
2766 | ||
2767 | match *self { | |
ff7c6d11 | 2768 | Use(ref place) => write!(fmt, "{:?}", place), |
5099ac24 | 2769 | Repeat(ref a, b) => { |
ba9703b0 XL |
2770 | write!(fmt, "[{:?}; ", a)?; |
2771 | pretty_print_const(b, fmt, false)?; | |
2772 | write!(fmt, "]") | |
2773 | } | |
9cc50fc6 | 2774 | Len(ref a) => write!(fmt, "Len({:?})", a), |
ff7c6d11 XL |
2775 | Cast(ref kind, ref place, ref ty) => { |
2776 | write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind) | |
2777 | } | |
6a06907d XL |
2778 | BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{:?}({:?}, {:?})", op, a, b), |
2779 | CheckedBinaryOp(ref op, box (ref a, ref b)) => { | |
3157f602 XL |
2780 | write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b) |
2781 | } | |
e9174d1e | 2782 | UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), |
ff7c6d11 | 2783 | Discriminant(ref place) => write!(fmt, "discriminant({:?})", place), |
7cac9316 | 2784 | NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), |
f9f354fc XL |
2785 | ThreadLocalRef(did) => ty::tls::with(|tcx| { |
2786 | let muta = tcx.static_mutability(did).unwrap().prefix_str(); | |
2787 | write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did)) | |
2788 | }), | |
ff7c6d11 | 2789 | Ref(region, borrow_kind, ref place) => { |
9cc50fc6 SL |
2790 | let kind_str = match borrow_kind { |
2791 | BorrowKind::Shared => "", | |
0bf4aa26 | 2792 | BorrowKind::Shallow => "shallow ", |
2c00a5a8 | 2793 | BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", |
9cc50fc6 | 2794 | }; |
041b39d2 | 2795 | |
3b2f2976 | 2796 | // When printing regions, add trailing space if necessary. |
532ac7d7 XL |
2797 | let print_region = ty::tls::with(|tcx| { |
2798 | tcx.sess.verbose() || tcx.sess.opts.debugging_opts.identify_regions | |
2799 | }); | |
2800 | let region = if print_region { | |
8faf50e0 | 2801 | let mut region = region.to_string(); |
74b04a01 | 2802 | if !region.is_empty() { |
94b46f34 XL |
2803 | region.push(' '); |
2804 | } | |
041b39d2 XL |
2805 | region |
2806 | } else { | |
3b2f2976 | 2807 | // Do not even print 'static |
b7449926 | 2808 | String::new() |
041b39d2 | 2809 | }; |
ff7c6d11 | 2810 | write!(fmt, "&{}{}{:?}", region, kind_str, place) |
9cc50fc6 SL |
2811 | } |
2812 | ||
dfeec247 XL |
2813 | AddressOf(mutability, ref place) => { |
2814 | let kind_str = match mutability { | |
2815 | Mutability::Mut => "mut", | |
2816 | Mutability::Not => "const", | |
2817 | }; | |
2818 | ||
2819 | write!(fmt, "&raw {} {:?}", kind_str, place) | |
2820 | } | |
2821 | ||
ff7c6d11 | 2822 | Aggregate(ref kind, ref places) => { |
ba9703b0 XL |
2823 | let fmt_tuple = |fmt: &mut Formatter<'_>, name: &str| { |
2824 | let mut tuple_fmt = fmt.debug_tuple(name); | |
ff7c6d11 XL |
2825 | for place in places { |
2826 | tuple_fmt.field(place); | |
9cc50fc6 SL |
2827 | } |
2828 | tuple_fmt.finish() | |
ba9703b0 | 2829 | }; |
9cc50fc6 | 2830 | |
cc61c64b | 2831 | match **kind { |
ff7c6d11 | 2832 | AggregateKind::Array(_) => write!(fmt, "{:?}", places), |
9cc50fc6 | 2833 | |
ba9703b0 XL |
2834 | AggregateKind::Tuple => { |
2835 | if places.is_empty() { | |
2836 | write!(fmt, "()") | |
2837 | } else { | |
2838 | fmt_tuple(fmt, "") | |
2839 | } | |
2840 | } | |
9cc50fc6 | 2841 | |
a2a8927a XL |
2842 | AggregateKind::Adt(adt_did, variant, substs, _user_ty, _) => { |
2843 | ty::tls::with(|tcx| { | |
5e7ed085 | 2844 | let variant_def = &tcx.adt_def(adt_did).variant(variant); |
29967ef6 | 2845 | let substs = tcx.lift(substs).expect("could not lift for printing"); |
5e7ed085 FG |
2846 | let name = FmtPrinter::new(tcx, Namespace::ValueNS) |
2847 | .print_def_path(variant_def.def_id, substs)? | |
2848 | .into_buffer(); | |
a2a8927a XL |
2849 | |
2850 | match variant_def.ctor_kind { | |
2851 | CtorKind::Const => fmt.write_str(&name), | |
2852 | CtorKind::Fn => fmt_tuple(fmt, &name), | |
2853 | CtorKind::Fictive => { | |
2854 | let mut struct_fmt = fmt.debug_struct(&name); | |
2855 | for (field, place) in iter::zip(&variant_def.fields, places) { | |
5099ac24 | 2856 | struct_fmt.field(field.name.as_str(), place); |
a2a8927a XL |
2857 | } |
2858 | struct_fmt.finish() | |
9cc50fc6 | 2859 | } |
9cc50fc6 | 2860 | } |
a2a8927a | 2861 | }) |
9cc50fc6 SL |
2862 | } |
2863 | ||
60c5eb7d | 2864 | AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| { |
f9f354fc | 2865 | if let Some(def_id) = def_id.as_local() { |
041b39d2 | 2866 | let name = if tcx.sess.opts.debugging_opts.span_free_formats { |
29967ef6 | 2867 | let substs = tcx.lift(substs).unwrap(); |
60c5eb7d XL |
2868 | format!( |
2869 | "[closure@{}]", | |
f9f354fc | 2870 | tcx.def_path_str_with_substs(def_id.to_def_id(), substs), |
60c5eb7d | 2871 | ) |
041b39d2 | 2872 | } else { |
5099ac24 | 2873 | let span = tcx.def_span(def_id); |
17df50a5 XL |
2874 | format!( |
2875 | "[closure@{}]", | |
2876 | tcx.sess.source_map().span_to_diagnostic_string(span) | |
2877 | ) | |
041b39d2 | 2878 | }; |
9cc50fc6 SL |
2879 | let mut struct_fmt = fmt.debug_struct(&name); |
2880 | ||
17df50a5 | 2881 | // FIXME(project-rfc-2229#48): This should be a list of capture names/places |
f9f354fc | 2882 | if let Some(upvars) = tcx.upvars_mentioned(def_id) { |
cdc7bbd5 | 2883 | for (&var_id, place) in iter::zip(upvars.keys(), places) { |
dc9dc135 | 2884 | let var_name = tcx.hir().name(var_id); |
a2a8927a | 2885 | struct_fmt.field(var_name.as_str(), place); |
9cc50fc6 | 2886 | } |
48663c56 | 2887 | } |
9cc50fc6 SL |
2888 | |
2889 | struct_fmt.finish() | |
2890 | } else { | |
2891 | write!(fmt, "[closure]") | |
2892 | } | |
2893 | }), | |
ea8adc8c XL |
2894 | |
2895 | AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| { | |
f9f354fc | 2896 | if let Some(def_id) = def_id.as_local() { |
5099ac24 | 2897 | let name = format!("[generator@{:?}]", tcx.def_span(def_id)); |
ea8adc8c XL |
2898 | let mut struct_fmt = fmt.debug_struct(&name); |
2899 | ||
17df50a5 | 2900 | // FIXME(project-rfc-2229#48): This should be a list of capture names/places |
f9f354fc | 2901 | if let Some(upvars) = tcx.upvars_mentioned(def_id) { |
cdc7bbd5 | 2902 | for (&var_id, place) in iter::zip(upvars.keys(), places) { |
dc9dc135 | 2903 | let var_name = tcx.hir().name(var_id); |
a2a8927a | 2904 | struct_fmt.field(var_name.as_str(), place); |
ea8adc8c | 2905 | } |
48663c56 | 2906 | } |
ea8adc8c XL |
2907 | |
2908 | struct_fmt.finish() | |
2909 | } else { | |
2910 | write!(fmt, "[generator]") | |
2911 | } | |
2912 | }), | |
9cc50fc6 SL |
2913 | } |
2914 | } | |
c295e0f8 XL |
2915 | |
2916 | ShallowInitBox(ref place, ref ty) => { | |
2917 | write!(fmt, "ShallowInitBox({:?}, {:?})", place, ty) | |
2918 | } | |
e9174d1e SL |
2919 | } |
2920 | } | |
2921 | } | |
2922 | ||
2923 | /////////////////////////////////////////////////////////////////////////// | |
7453a54e SL |
2924 | /// Constants |
2925 | /// | |
2926 | /// Two constants are equal if they are the same constant. Note that | |
1b1a35ee XL |
2927 | /// this does not necessarily mean that they are `==` in Rust. In |
2928 | /// particular, one must be wary of `NaN`! | |
e9174d1e | 2929 | |
5099ac24 | 2930 | #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] |
b039eaaf SL |
2931 | pub struct Constant<'tcx> { |
2932 | pub span: Span, | |
b7449926 XL |
2933 | |
2934 | /// Optional user-given type: for something like | |
2935 | /// `collect::<Vec<_>>`, this would be present and would | |
2936 | /// indicate that `Vec<_>` was explicitly specified. | |
2937 | /// | |
2938 | /// Needed for NLL to impose user-given type constraints. | |
0731742a | 2939 | pub user_ty: Option<UserTypeAnnotationIndex>, |
b7449926 | 2940 | |
6a06907d XL |
2941 | pub literal: ConstantKind<'tcx>, |
2942 | } | |
2943 | ||
5099ac24 | 2944 | #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)] |
cdc7bbd5 | 2945 | #[derive(Lift)] |
6a06907d XL |
2946 | pub enum ConstantKind<'tcx> { |
2947 | /// This constant came from the type system | |
5099ac24 | 2948 | Ty(ty::Const<'tcx>), |
6a06907d XL |
2949 | /// This constant cannot go back into the type system, as it represents |
2950 | /// something the type system cannot handle (e.g. pointers). | |
2951 | Val(interpret::ConstValue<'tcx>, Ty<'tcx>), | |
0bf4aa26 XL |
2952 | } |
2953 | ||
a2a8927a | 2954 | impl<'tcx> Constant<'tcx> { |
60c5eb7d | 2955 | pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> { |
5099ac24 | 2956 | match self.literal.try_to_scalar() { |
136023e0 | 2957 | Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) { |
f9f354fc XL |
2958 | GlobalAlloc::Static(def_id) => { |
2959 | assert!(!tcx.is_thread_local_static(def_id)); | |
2960 | Some(def_id) | |
dfeec247 | 2961 | } |
f9f354fc | 2962 | _ => None, |
60c5eb7d XL |
2963 | }, |
2964 | _ => None, | |
2965 | } | |
2966 | } | |
17df50a5 | 2967 | #[inline] |
6a06907d XL |
2968 | pub fn ty(&self) -> Ty<'tcx> { |
2969 | self.literal.ty() | |
2970 | } | |
2971 | } | |
2972 | ||
a2a8927a | 2973 | impl<'tcx> ConstantKind<'tcx> { |
6a06907d | 2974 | /// Returns `None` if the constant is not trivially safe for use in the type system. |
923072b8 | 2975 | #[inline] |
5099ac24 | 2976 | pub fn const_for_ty(&self) -> Option<ty::Const<'tcx>> { |
6a06907d | 2977 | match self { |
5099ac24 | 2978 | ConstantKind::Ty(c) => Some(*c), |
6a06907d XL |
2979 | ConstantKind::Val(..) => None, |
2980 | } | |
2981 | } | |
2982 | ||
923072b8 | 2983 | #[inline(always)] |
6a06907d XL |
2984 | pub fn ty(&self) -> Ty<'tcx> { |
2985 | match self { | |
5099ac24 FG |
2986 | ConstantKind::Ty(c) => c.ty(), |
2987 | ConstantKind::Val(_, ty) => *ty, | |
6a06907d XL |
2988 | } |
2989 | } | |
2990 | ||
923072b8 FG |
2991 | #[inline] |
2992 | pub fn try_to_value(self, tcx: TyCtxt<'tcx>) -> Option<interpret::ConstValue<'tcx>> { | |
04454e1e | 2993 | match self { |
923072b8 FG |
2994 | ConstantKind::Ty(c) => match c.kind() { |
2995 | ty::ConstKind::Value(valtree) => Some(tcx.valtree_to_const_val((c.ty(), valtree))), | |
04454e1e FG |
2996 | _ => None, |
2997 | }, | |
6a06907d XL |
2998 | ConstantKind::Val(val, _) => Some(val), |
2999 | } | |
3000 | } | |
3001 | ||
3002 | #[inline] | |
3003 | pub fn try_to_scalar(self) -> Option<Scalar> { | |
923072b8 FG |
3004 | match self { |
3005 | ConstantKind::Ty(c) => match c.kind() { | |
3006 | ty::ConstKind::Value(valtree) => match valtree { | |
3007 | ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)), | |
3008 | ty::ValTree::Branch(_) => None, | |
3009 | }, | |
3010 | _ => None, | |
3011 | }, | |
3012 | ConstantKind::Val(val, _) => val.try_to_scalar(), | |
3013 | } | |
6a06907d XL |
3014 | } |
3015 | ||
3016 | #[inline] | |
3017 | pub fn try_to_scalar_int(self) -> Option<ScalarInt> { | |
923072b8 | 3018 | Some(self.try_to_scalar()?.assert_int()) |
6a06907d XL |
3019 | } |
3020 | ||
3021 | #[inline] | |
3022 | pub fn try_to_bits(self, size: Size) -> Option<u128> { | |
3023 | self.try_to_scalar_int()?.to_bits(size).ok() | |
3024 | } | |
3025 | ||
3026 | #[inline] | |
3027 | pub fn try_to_bool(self) -> Option<bool> { | |
3028 | self.try_to_scalar_int()?.try_into().ok() | |
3029 | } | |
3030 | ||
04454e1e FG |
3031 | #[inline] |
3032 | pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { | |
3033 | match self { | |
3034 | Self::Ty(c) => { | |
923072b8 | 3035 | if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) { |
04454e1e FG |
3036 | match val { |
3037 | Ok(val) => Self::Val(val, c.ty()), | |
3038 | Err(_) => Self::Ty(tcx.const_error(self.ty())), | |
3039 | } | |
3040 | } else { | |
3041 | self | |
3042 | } | |
3043 | } | |
3044 | Self::Val(_, _) => self, | |
3045 | } | |
3046 | } | |
3047 | ||
3048 | /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. | |
3049 | #[inline] | |
3050 | pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { | |
3051 | self.try_eval_bits(tcx, param_env, ty) | |
3052 | .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self)) | |
3053 | } | |
3054 | ||
6a06907d XL |
3055 | #[inline] |
3056 | pub fn try_eval_bits( | |
3057 | &self, | |
3058 | tcx: TyCtxt<'tcx>, | |
3059 | param_env: ty::ParamEnv<'tcx>, | |
3060 | ty: Ty<'tcx>, | |
3061 | ) -> Option<u128> { | |
3062 | match self { | |
3063 | Self::Ty(ct) => ct.try_eval_bits(tcx, param_env, ty), | |
3064 | Self::Val(val, t) => { | |
3065 | assert_eq!(*t, ty); | |
3066 | let size = | |
3067 | tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; | |
3068 | val.try_to_bits(size) | |
3069 | } | |
3070 | } | |
3071 | } | |
3072 | ||
3073 | #[inline] | |
3074 | pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> { | |
3075 | match self { | |
3076 | Self::Ty(ct) => ct.try_eval_bool(tcx, param_env), | |
3077 | Self::Val(val, _) => val.try_to_bool(), | |
3078 | } | |
3079 | } | |
3080 | ||
3081 | #[inline] | |
3082 | pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u64> { | |
3083 | match self { | |
3084 | Self::Ty(ct) => ct.try_eval_usize(tcx, param_env), | |
3085 | Self::Val(val, _) => val.try_to_machine_usize(tcx), | |
3086 | } | |
3087 | } | |
5e7ed085 | 3088 | |
923072b8 FG |
3089 | #[inline] |
3090 | pub fn from_value(val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self { | |
3091 | Self::Val(val, ty) | |
3092 | } | |
3093 | ||
04454e1e FG |
3094 | pub fn from_bits( |
3095 | tcx: TyCtxt<'tcx>, | |
3096 | bits: u128, | |
3097 | param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, | |
3098 | ) -> Self { | |
3099 | let size = tcx | |
3100 | .layout_of(param_env_ty) | |
3101 | .unwrap_or_else(|e| { | |
3102 | bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e) | |
3103 | }) | |
3104 | .size; | |
3105 | let cv = ConstValue::Scalar(Scalar::from_uint(bits, size)); | |
3106 | ||
3107 | Self::Val(cv, param_env_ty.value) | |
3108 | } | |
3109 | ||
923072b8 | 3110 | #[inline] |
5e7ed085 FG |
3111 | pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self { |
3112 | let cv = ConstValue::from_bool(v); | |
3113 | Self::Val(cv, tcx.types.bool) | |
3114 | } | |
3115 | ||
923072b8 | 3116 | #[inline] |
04454e1e | 3117 | pub fn zero_sized(ty: Ty<'tcx>) -> Self { |
5e7ed085 FG |
3118 | let cv = ConstValue::Scalar(Scalar::ZST); |
3119 | Self::Val(cv, ty) | |
3120 | } | |
3121 | ||
3122 | pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self { | |
3123 | let ty = tcx.types.usize; | |
04454e1e FG |
3124 | Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty)) |
3125 | } | |
5e7ed085 | 3126 | |
923072b8 FG |
3127 | #[inline] |
3128 | pub fn from_scalar(_tcx: TyCtxt<'tcx>, s: Scalar, ty: Ty<'tcx>) -> Self { | |
3129 | let val = ConstValue::Scalar(s); | |
3130 | Self::Val(val, ty) | |
3131 | } | |
3132 | ||
04454e1e FG |
3133 | /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly |
3134 | /// converted to a constant, everything else becomes `Unevaluated`. | |
3135 | pub fn from_anon_const( | |
3136 | tcx: TyCtxt<'tcx>, | |
3137 | def_id: LocalDefId, | |
3138 | param_env: ty::ParamEnv<'tcx>, | |
3139 | ) -> Self { | |
3140 | Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env) | |
3141 | } | |
3142 | ||
923072b8 FG |
3143 | #[instrument(skip(tcx), level = "debug")] |
3144 | pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { | |
3145 | let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); | |
3146 | let body_id = match tcx.hir().get(hir_id) { | |
3147 | hir::Node::AnonConst(ac) => ac.body, | |
3148 | _ => span_bug!( | |
3149 | tcx.def_span(def_id.to_def_id()), | |
3150 | "from_inline_const can only process anonymous constants" | |
3151 | ), | |
3152 | }; | |
3153 | let expr = &tcx.hir().body(body_id).value; | |
3154 | let ty = tcx.typeck(def_id).node_type(hir_id); | |
3155 | ||
3156 | let lit_input = match expr.kind { | |
3157 | hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), | |
3158 | hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { | |
3159 | hir::ExprKind::Lit(ref lit) => { | |
3160 | Some(LitToConstInput { lit: &lit.node, ty, neg: true }) | |
3161 | } | |
3162 | _ => None, | |
3163 | }, | |
3164 | _ => None, | |
3165 | }; | |
3166 | if let Some(lit_input) = lit_input { | |
3167 | // If an error occurred, ignore that it's a literal and leave reporting the error up to | |
3168 | // mir. | |
3169 | match tcx.at(expr.span).lit_to_mir_constant(lit_input) { | |
3170 | Ok(c) => return c, | |
3171 | Err(_) => {} | |
3172 | } | |
3173 | } | |
3174 | ||
3175 | let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); | |
3176 | let parent_substs = | |
3177 | tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id)); | |
3178 | let substs = | |
3179 | ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty }) | |
3180 | .substs; | |
3181 | let uneval_const = tcx.mk_const(ty::ConstS { | |
3182 | kind: ty::ConstKind::Unevaluated(ty::Unevaluated { | |
3183 | def: ty::WithOptConstParam::unknown(def_id).to_global(), | |
3184 | substs, | |
3185 | promoted: None, | |
3186 | }), | |
3187 | ty, | |
3188 | }); | |
3189 | debug!(?uneval_const); | |
3190 | debug_assert!(!uneval_const.has_free_regions()); | |
3191 | ||
3192 | Self::Ty(uneval_const) | |
3193 | } | |
3194 | ||
04454e1e FG |
3195 | #[instrument(skip(tcx), level = "debug")] |
3196 | fn from_opt_const_arg_anon_const( | |
3197 | tcx: TyCtxt<'tcx>, | |
3198 | def: ty::WithOptConstParam<LocalDefId>, | |
3199 | param_env: ty::ParamEnv<'tcx>, | |
3200 | ) -> Self { | |
3201 | let body_id = match tcx.hir().get_by_def_id(def.did) { | |
3202 | hir::Node::AnonConst(ac) => ac.body, | |
3203 | _ => span_bug!( | |
3204 | tcx.def_span(def.did.to_def_id()), | |
3205 | "from_anon_const can only process anonymous constants" | |
3206 | ), | |
3207 | }; | |
3208 | ||
3209 | let expr = &tcx.hir().body(body_id).value; | |
3210 | debug!(?expr); | |
3211 | ||
3212 | // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments | |
3213 | // currently have to be wrapped in curly brackets, so it's necessary to special-case. | |
3214 | let expr = match &expr.kind { | |
3215 | hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { | |
3216 | block.expr.as_ref().unwrap() | |
3217 | } | |
3218 | _ => expr, | |
3219 | }; | |
923072b8 | 3220 | debug!("expr.kind: {:?}", expr.kind); |
04454e1e FG |
3221 | |
3222 | let ty = tcx.type_of(def.def_id_for_type_of()); | |
923072b8 | 3223 | debug!(?ty); |
04454e1e FG |
3224 | |
3225 | // FIXME(const_generics): We currently have to special case parameters because `min_const_generics` | |
3226 | // does not provide the parents generics to anonymous constants. We still allow generic const | |
3227 | // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to | |
3228 | // ever try to substitute the generic parameters in their bodies. | |
3229 | // | |
3230 | // While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does | |
3231 | // cause issues if we were to remove that special-case and try to evaluate the constant instead. | |
3232 | use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; | |
3233 | match expr.kind { | |
3234 | ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { | |
3235 | // Find the name and index of the const parameter by indexing the generics of | |
3236 | // the parent item and construct a `ParamConst`. | |
3237 | let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); | |
3238 | let item_id = tcx.hir().get_parent_node(hir_id); | |
3239 | let item_def_id = tcx.hir().local_def_id(item_id); | |
3240 | let generics = tcx.generics_of(item_def_id.to_def_id()); | |
3241 | let index = generics.param_def_id_to_index[&def_id]; | |
3242 | let name = tcx.hir().name(hir_id); | |
3243 | let ty_const = tcx.mk_const(ty::ConstS { | |
923072b8 | 3244 | kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)), |
04454e1e FG |
3245 | ty, |
3246 | }); | |
923072b8 | 3247 | debug!(?ty_const); |
04454e1e FG |
3248 | |
3249 | return Self::Ty(ty_const); | |
3250 | } | |
3251 | _ => {} | |
3252 | } | |
3253 | ||
3254 | let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); | |
3255 | let parent_substs = if let Some(parent_hir_id) = tcx.hir().find_parent_node(hir_id) { | |
3256 | if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) { | |
3257 | InternalSubsts::identity_for_item(tcx, parent_did.to_def_id()) | |
3258 | } else { | |
3259 | tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter()) | |
3260 | } | |
3261 | } else { | |
3262 | tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter()) | |
3263 | }; | |
3264 | debug!(?parent_substs); | |
3265 | ||
3266 | let did = def.did.to_def_id(); | |
3267 | let child_substs = InternalSubsts::identity_for_item(tcx, did); | |
3268 | let substs = tcx.mk_substs(parent_substs.into_iter().chain(child_substs.into_iter())); | |
3269 | debug!(?substs); | |
3270 | ||
3271 | let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); | |
3272 | let span = tcx.hir().span(hir_id); | |
3273 | let uneval = ty::Unevaluated::new(def.to_global(), substs); | |
3274 | debug!(?span, ?param_env); | |
3275 | ||
3276 | match tcx.const_eval_resolve(param_env, uneval, Some(span)) { | |
923072b8 FG |
3277 | Ok(val) => { |
3278 | debug!("evaluated const value: {:?}", val); | |
3279 | Self::Val(val, ty) | |
3280 | } | |
04454e1e | 3281 | Err(_) => { |
923072b8 | 3282 | debug!("error encountered during evaluation"); |
04454e1e FG |
3283 | // Error was handled in `const_eval_resolve`. Here we just create a |
3284 | // new unevaluated const and error hard later in codegen | |
3285 | let ty_const = tcx.mk_const(ty::ConstS { | |
923072b8 | 3286 | kind: ty::ConstKind::Unevaluated(ty::Unevaluated { |
04454e1e FG |
3287 | def: def.to_global(), |
3288 | substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), | |
3289 | promoted: None, | |
3290 | }), | |
3291 | ty, | |
3292 | }); | |
923072b8 | 3293 | debug!(?ty_const); |
04454e1e FG |
3294 | |
3295 | Self::Ty(ty_const) | |
3296 | } | |
3297 | } | |
5e7ed085 | 3298 | } |
923072b8 FG |
3299 | |
3300 | pub fn from_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self { | |
3301 | match c.kind() { | |
3302 | ty::ConstKind::Value(valtree) => { | |
3303 | let const_val = tcx.valtree_to_const_val((c.ty(), valtree)); | |
3304 | Self::Val(const_val, c.ty()) | |
3305 | } | |
3306 | _ => Self::Ty(c), | |
3307 | } | |
3308 | } | |
60c5eb7d XL |
3309 | } |
3310 | ||
0bf4aa26 XL |
3311 | /// A collection of projections into user types. |
3312 | /// | |
3313 | /// They are projections because a binding can occur a part of a | |
3314 | /// parent pattern that has been ascribed a type. | |
3315 | /// | |
3316 | /// Its a collection because there can be multiple type ascriptions on | |
3317 | /// the path from the root of the pattern down to the binding itself. | |
3318 | /// | |
3319 | /// An example: | |
3320 | /// | |
04454e1e | 3321 | /// ```ignore (illustrative) |
0bf4aa26 XL |
3322 | /// struct S<'a>((i32, &'a str), String); |
3323 | /// let S((_, w): (i32, &'static str), _): S = ...; | |
3324 | /// // ------ ^^^^^^^^^^^^^^^^^^^ (1) | |
3325 | /// // --------------------------------- ^ (2) | |
3326 | /// ``` | |
3327 | /// | |
3328 | /// The highlights labelled `(1)` show the subpattern `(_, w)` being | |
3329 | /// ascribed the type `(i32, &'static str)`. | |
3330 | /// | |
3331 | /// The highlights labelled `(2)` show the whole pattern being | |
3332 | /// ascribed the type `S`. | |
3333 | /// | |
3334 | /// In this example, when we descend to `w`, we will have built up the | |
3335 | /// following two projected types: | |
3336 | /// | |
3337 | /// * base: `S`, projection: `(base.0).1` | |
3338 | /// * base: `(i32, &'static str)`, projection: `base.1` | |
3339 | /// | |
3340 | /// The first will lead to the constraint `w: &'1 str` (for some | |
3341 | /// inferred region `'1`). The second will lead to the constraint `w: | |
3342 | /// &'static str`. | |
3dfed10e | 3343 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] |
532ac7d7 | 3344 | pub struct UserTypeProjections { |
f9f354fc | 3345 | pub contents: Vec<(UserTypeProjection, Span)>, |
0bf4aa26 XL |
3346 | } |
3347 | ||
532ac7d7 | 3348 | impl<'tcx> UserTypeProjections { |
0bf4aa26 XL |
3349 | pub fn none() -> Self { |
3350 | UserTypeProjections { contents: vec![] } | |
3351 | } | |
3352 | ||
f9f354fc XL |
3353 | pub fn is_empty(&self) -> bool { |
3354 | self.contents.is_empty() | |
3355 | } | |
3356 | ||
dfeec247 XL |
3357 | pub fn projections_and_spans( |
3358 | &self, | |
3359 | ) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator { | |
0bf4aa26 XL |
3360 | self.contents.iter() |
3361 | } | |
3362 | ||
dfeec247 | 3363 | pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator { |
0bf4aa26 XL |
3364 | self.contents.iter().map(|&(ref user_type, _span)| user_type) |
3365 | } | |
0731742a | 3366 | |
416331ca | 3367 | pub fn push_projection(mut self, user_ty: &UserTypeProjection, span: Span) -> Self { |
0731742a XL |
3368 | self.contents.push((user_ty.clone(), span)); |
3369 | self | |
3370 | } | |
3371 | ||
3372 | fn map_projections( | |
3373 | mut self, | |
416331ca | 3374 | mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection, |
0731742a | 3375 | ) -> Self { |
3c0e092e | 3376 | self.contents = self.contents.into_iter().map(|(proj, span)| (f(proj), span)).collect(); |
0731742a XL |
3377 | self |
3378 | } | |
3379 | ||
3380 | pub fn index(self) -> Self { | |
3381 | self.map_projections(|pat_ty_proj| pat_ty_proj.index()) | |
3382 | } | |
3383 | ||
1b1a35ee | 3384 | pub fn subslice(self, from: u64, to: u64) -> Self { |
0731742a XL |
3385 | self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) |
3386 | } | |
3387 | ||
3388 | pub fn deref(self) -> Self { | |
3389 | self.map_projections(|pat_ty_proj| pat_ty_proj.deref()) | |
3390 | } | |
3391 | ||
3392 | pub fn leaf(self, field: Field) -> Self { | |
3393 | self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field)) | |
3394 | } | |
3395 | ||
5e7ed085 | 3396 | pub fn variant(self, adt_def: AdtDef<'tcx>, variant_index: VariantIdx, field: Field) -> Self { |
0731742a XL |
3397 | self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field)) |
3398 | } | |
0bf4aa26 XL |
3399 | } |
3400 | ||
3401 | /// Encodes the effect of a user-supplied type annotation on the | |
3402 | /// subcomponents of a pattern. The effect is determined by applying the | |
5e7ed085 | 3403 | /// given list of projections to some underlying base type. Often, |
0bf4aa26 XL |
3404 | /// the projection element list `projs` is empty, in which case this |
3405 | /// directly encodes a type in `base`. But in the case of complex patterns with | |
3406 | /// subpatterns and bindings, we want to apply only a *part* of the type to a variable, | |
3407 | /// in which case the `projs` vector is used. | |
3408 | /// | |
3409 | /// Examples: | |
3410 | /// | |
3411 | /// * `let x: T = ...` -- here, the `projs` vector is empty. | |
3412 | /// | |
3413 | /// * `let (x, _): T = ...` -- here, the `projs` vector would contain | |
3414 | /// `field[0]` (aka `.0`), indicating that the type of `s` is | |
3415 | /// determined by finding the type of the `.0` field from `T`. | |
6a06907d | 3416 | #[derive(Clone, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] |
532ac7d7 | 3417 | pub struct UserTypeProjection { |
0731742a | 3418 | pub base: UserTypeAnnotationIndex, |
dc9dc135 | 3419 | pub projs: Vec<ProjectionKind>, |
0bf4aa26 XL |
3420 | } |
3421 | ||
416331ca | 3422 | impl Copy for ProjectionKind {} |
0bf4aa26 | 3423 | |
532ac7d7 | 3424 | impl UserTypeProjection { |
0731742a XL |
3425 | pub(crate) fn index(mut self) -> Self { |
3426 | self.projs.push(ProjectionElem::Index(())); | |
3427 | self | |
3428 | } | |
3429 | ||
1b1a35ee | 3430 | pub(crate) fn subslice(mut self, from: u64, to: u64) -> Self { |
60c5eb7d | 3431 | self.projs.push(ProjectionElem::Subslice { from, to, from_end: true }); |
0731742a XL |
3432 | self |
3433 | } | |
3434 | ||
3435 | pub(crate) fn deref(mut self) -> Self { | |
3436 | self.projs.push(ProjectionElem::Deref); | |
3437 | self | |
3438 | } | |
3439 | ||
3440 | pub(crate) fn leaf(mut self, field: Field) -> Self { | |
3441 | self.projs.push(ProjectionElem::Field(field, ())); | |
3442 | self | |
3443 | } | |
3444 | ||
3445 | pub(crate) fn variant( | |
3446 | mut self, | |
5e7ed085 | 3447 | adt_def: AdtDef<'_>, |
0731742a XL |
3448 | variant_index: VariantIdx, |
3449 | field: Field, | |
3450 | ) -> Self { | |
532ac7d7 | 3451 | self.projs.push(ProjectionElem::Downcast( |
5e7ed085 | 3452 | Some(adt_def.variant(variant_index).name), |
416331ca XL |
3453 | variant_index, |
3454 | )); | |
0731742a XL |
3455 | self.projs.push(ProjectionElem::Field(field, ())); |
3456 | self | |
3457 | } | |
3458 | } | |
3459 | ||
fc512014 | 3460 | TrivialTypeFoldableAndLiftImpls! { ProjectionKind, } |
0bf4aa26 | 3461 | |
532ac7d7 | 3462 | impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { |
923072b8 | 3463 | fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { |
a2a8927a XL |
3464 | Ok(UserTypeProjection { |
3465 | base: self.base.try_fold_with(folder)?, | |
3466 | projs: self.projs.try_fold_with(folder)?, | |
3467 | }) | |
0bf4aa26 XL |
3468 | } |
3469 | ||
923072b8 | 3470 | fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> { |
0bf4aa26 XL |
3471 | self.base.visit_with(visitor) |
3472 | // Note: there's nothing in `self.proj` to visit. | |
3473 | } | |
3474 | } | |
3475 | ||
e74abb32 | 3476 | rustc_index::newtype_index! { |
b7449926 | 3477 | pub struct Promoted { |
532ac7d7 | 3478 | derive [HashStable] |
b7449926 XL |
3479 | DEBUG_FORMAT = "promoted[{}]" |
3480 | } | |
3481 | } | |
abe05a73 | 3482 | |
9cc50fc6 | 3483 | impl<'tcx> Debug for Constant<'tcx> { |
0bf4aa26 | 3484 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { |
dc9dc135 | 3485 | write!(fmt, "{}", self) |
9cc50fc6 SL |
3486 | } |
3487 | } | |
3488 | ||
dc9dc135 XL |
3489 | impl<'tcx> Display for Constant<'tcx> { |
3490 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { | |
6a06907d | 3491 | match self.ty().kind() { |
3dfed10e XL |
3492 | ty::FnDef(..) => {} |
3493 | _ => write!(fmt, "const ")?, | |
3494 | } | |
cdc7bbd5 XL |
3495 | Display::fmt(&self.literal, fmt) |
3496 | } | |
3497 | } | |
3498 | ||
3499 | impl<'tcx> Display for ConstantKind<'tcx> { | |
3500 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { | |
3501 | match *self { | |
6a06907d XL |
3502 | ConstantKind::Ty(c) => pretty_print_const(c, fmt, true), |
3503 | ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true), | |
3504 | } | |
dc9dc135 | 3505 | } |
9cc50fc6 | 3506 | } |
3157f602 | 3507 | |
a2a8927a | 3508 | fn pretty_print_const<'tcx>( |
5099ac24 | 3509 | c: ty::Const<'tcx>, |
ba9703b0 XL |
3510 | fmt: &mut Formatter<'_>, |
3511 | print_types: bool, | |
3512 | ) -> fmt::Result { | |
3513 | use crate::ty::print::PrettyPrinter; | |
3514 | ty::tls::with(|tcx| { | |
29967ef6 | 3515 | let literal = tcx.lift(c).unwrap(); |
5e7ed085 | 3516 | let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); |
ba9703b0 | 3517 | cx.print_alloc_ids = true; |
5e7ed085 FG |
3518 | let cx = cx.pretty_print_const(literal, print_types)?; |
3519 | fmt.write_str(&cx.into_buffer())?; | |
ba9703b0 XL |
3520 | Ok(()) |
3521 | }) | |
3522 | } | |
3523 | ||
923072b8 FG |
3524 | fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result { |
3525 | fmt.write_str("b\"")?; | |
3526 | for &c in byte_str { | |
3527 | for e in std::ascii::escape_default(c) { | |
3528 | fmt.write_char(e as char)?; | |
3529 | } | |
3530 | } | |
3531 | fmt.write_str("\"")?; | |
3532 | ||
3533 | Ok(()) | |
3534 | } | |
3535 | ||
3536 | fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec<ConstantKind<'tcx>>) -> fmt::Result { | |
3537 | let mut first = true; | |
3538 | for elem in elems { | |
3539 | if !first { | |
3540 | fmt.write_str(", ")?; | |
3541 | } | |
3542 | fmt.write_str(&format!("{}", elem))?; | |
3543 | first = false; | |
3544 | } | |
3545 | Ok(()) | |
3546 | } | |
3547 | ||
3548 | // FIXME: Move that into `mir/pretty.rs`. | |
a2a8927a | 3549 | fn pretty_print_const_value<'tcx>( |
923072b8 | 3550 | ct: ConstValue<'tcx>, |
6a06907d XL |
3551 | ty: Ty<'tcx>, |
3552 | fmt: &mut Formatter<'_>, | |
923072b8 | 3553 | print_ty: bool, |
6a06907d XL |
3554 | ) -> fmt::Result { |
3555 | use crate::ty::print::PrettyPrinter; | |
923072b8 | 3556 | |
6a06907d | 3557 | ty::tls::with(|tcx| { |
923072b8 | 3558 | let ct = tcx.lift(ct).unwrap(); |
6a06907d | 3559 | let ty = tcx.lift(ty).unwrap(); |
923072b8 FG |
3560 | |
3561 | if tcx.sess.verbose() { | |
3562 | fmt.write_str(&format!("ConstValue({:?}: {})", ct, ty))?; | |
3563 | return Ok(()); | |
3564 | } | |
3565 | ||
3566 | let u8_type = tcx.types.u8; | |
3567 | match (ct, ty.kind()) { | |
3568 | // Byte/string slices, printed as (byte) string literals. | |
3569 | (ConstValue::Slice { data, start, end }, ty::Ref(_, inner, _)) => { | |
3570 | match inner.kind() { | |
3571 | ty::Slice(t) => { | |
3572 | if *t == u8_type { | |
3573 | // The `inspect` here is okay since we checked the bounds, and there are | |
3574 | // no relocations (we have an active slice reference here). We don't use | |
3575 | // this result to affect interpreter execution. | |
3576 | let byte_str = data | |
3577 | .inner() | |
3578 | .inspect_with_uninit_and_ptr_outside_interpreter(start..end); | |
3579 | pretty_print_byte_str(fmt, byte_str)?; | |
3580 | return Ok(()); | |
3581 | } | |
3582 | } | |
3583 | ty::Str => { | |
3584 | // The `inspect` here is okay since we checked the bounds, and there are no | |
3585 | // relocations (we have an active `str` reference here). We don't use this | |
3586 | // result to affect interpreter execution. | |
3587 | let slice = data | |
3588 | .inner() | |
3589 | .inspect_with_uninit_and_ptr_outside_interpreter(start..end); | |
3590 | fmt.write_str(&format!("{:?}", String::from_utf8_lossy(slice)))?; | |
3591 | return Ok(()); | |
3592 | } | |
3593 | _ => {} | |
3594 | } | |
3595 | } | |
3596 | (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => { | |
3597 | let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap(); | |
3598 | // cast is ok because we already checked for pointer size (32 or 64 bit) above | |
3599 | let range = AllocRange { start: offset, size: Size::from_bytes(n) }; | |
3600 | let byte_str = alloc.inner().get_bytes(&tcx, range).unwrap(); | |
3601 | fmt.write_str("*")?; | |
3602 | pretty_print_byte_str(fmt, byte_str)?; | |
3603 | return Ok(()); | |
3604 | } | |
3605 | // Aggregates, printed as array/tuple/struct/variant construction syntax. | |
3606 | // | |
3607 | // NB: the `has_param_types_or_consts` check ensures that we can use | |
3608 | // the `destructure_const` query with an empty `ty::ParamEnv` without | |
3609 | // introducing ICEs (e.g. via `layout_of`) from missing bounds. | |
3610 | // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` | |
3611 | // to be able to destructure the tuple into `(0u8, *mut T) | |
3612 | // | |
3613 | // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the | |
3614 | // correct `ty::ParamEnv` to allow printing *all* constant values. | |
3615 | (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => { | |
3616 | let ct = tcx.lift(ct).unwrap(); | |
3617 | let ty = tcx.lift(ty).unwrap(); | |
3618 | if let Some(contents) = tcx.try_destructure_mir_constant( | |
3619 | ty::ParamEnv::reveal_all().and(ConstantKind::Val(ct, ty)), | |
3620 | ) { | |
3621 | let fields = contents.fields.iter().copied().collect::<Vec<_>>(); | |
3622 | match *ty.kind() { | |
3623 | ty::Array(..) => { | |
3624 | fmt.write_str("[")?; | |
3625 | comma_sep(fmt, fields)?; | |
3626 | fmt.write_str("]")?; | |
3627 | } | |
3628 | ty::Tuple(..) => { | |
3629 | fmt.write_str("(")?; | |
3630 | comma_sep(fmt, fields)?; | |
3631 | if contents.fields.len() == 1 { | |
3632 | fmt.write_str(",")?; | |
3633 | } | |
3634 | fmt.write_str(")")?; | |
3635 | } | |
3636 | ty::Adt(def, _) if def.variants().is_empty() => { | |
3637 | fmt.write_str(&format!("{{unreachable(): {}}}", ty))?; | |
3638 | } | |
3639 | ty::Adt(def, substs) => { | |
3640 | let variant_idx = contents | |
3641 | .variant | |
3642 | .expect("destructed mir constant of adt without variant idx"); | |
3643 | let variant_def = &def.variant(variant_idx); | |
3644 | let substs = tcx.lift(substs).unwrap(); | |
3645 | let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); | |
3646 | cx.print_alloc_ids = true; | |
3647 | let cx = cx.print_value_path(variant_def.def_id, substs)?; | |
3648 | fmt.write_str(&cx.into_buffer())?; | |
3649 | ||
3650 | match variant_def.ctor_kind { | |
3651 | CtorKind::Const => {} | |
3652 | CtorKind::Fn => { | |
3653 | fmt.write_str("(")?; | |
3654 | comma_sep(fmt, fields)?; | |
3655 | fmt.write_str(")")?; | |
3656 | } | |
3657 | CtorKind::Fictive => { | |
3658 | fmt.write_str(" {{ ")?; | |
3659 | let mut first = true; | |
3660 | for (field_def, field) in iter::zip(&variant_def.fields, fields) | |
3661 | { | |
3662 | if !first { | |
3663 | fmt.write_str(", ")?; | |
3664 | } | |
3665 | fmt.write_str(&format!("{}: {}", field_def.name, field))?; | |
3666 | first = false; | |
3667 | } | |
3668 | fmt.write_str(" }}")?; | |
3669 | } | |
3670 | } | |
3671 | } | |
3672 | _ => unreachable!(), | |
3673 | } | |
3674 | return Ok(()); | |
3675 | } else { | |
3676 | // Fall back to debug pretty printing for invalid constants. | |
3677 | fmt.write_str(&format!("{:?}", ct))?; | |
3678 | if print_ty { | |
3679 | fmt.write_str(&format!(": {}", ty))?; | |
3680 | } | |
3681 | return Ok(()); | |
3682 | }; | |
3683 | } | |
3684 | (ConstValue::Scalar(scalar), _) => { | |
3685 | let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); | |
3686 | cx.print_alloc_ids = true; | |
3687 | let ty = tcx.lift(ty).unwrap(); | |
3688 | cx = cx.pretty_print_const_scalar(scalar, ty, print_ty)?; | |
3689 | fmt.write_str(&cx.into_buffer())?; | |
3690 | return Ok(()); | |
3691 | } | |
3692 | // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading | |
3693 | // their fields instead of just dumping the memory. | |
3694 | _ => {} | |
3695 | } | |
3696 | // fallback | |
3697 | fmt.write_str(&format!("{:?}", ct))?; | |
3698 | if print_ty { | |
3699 | fmt.write_str(&format!(": {}", ty))?; | |
3700 | } | |
6a06907d XL |
3701 | Ok(()) |
3702 | }) | |
3703 | } | |
3704 | ||
dc9dc135 | 3705 | impl<'tcx> graph::DirectedGraph for Body<'tcx> { |
3157f602 | 3706 | type Node = BasicBlock; |
8faf50e0 | 3707 | } |
3157f602 | 3708 | |
dc9dc135 | 3709 | impl<'tcx> graph::WithNumNodes for Body<'tcx> { |
f9f354fc | 3710 | #[inline] |
94b46f34 XL |
3711 | fn num_nodes(&self) -> usize { |
3712 | self.basic_blocks.len() | |
3713 | } | |
8faf50e0 | 3714 | } |
3157f602 | 3715 | |
dc9dc135 | 3716 | impl<'tcx> graph::WithStartNode for Body<'tcx> { |
f9f354fc | 3717 | #[inline] |
94b46f34 XL |
3718 | fn start_node(&self) -> Self::Node { |
3719 | START_BLOCK | |
3720 | } | |
8faf50e0 | 3721 | } |
3157f602 | 3722 | |
dc9dc135 | 3723 | impl<'tcx> graph::WithSuccessors for Body<'tcx> { |
f9f354fc | 3724 | #[inline] |
dfeec247 | 3725 | fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter { |
923072b8 | 3726 | self.basic_blocks[node].terminator().successors() |
3157f602 XL |
3727 | } |
3728 | } | |
3729 | ||
dc9dc135 | 3730 | impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { |
3157f602 | 3731 | type Item = BasicBlock; |
923072b8 | 3732 | type Iter = Successors<'b>; |
3157f602 | 3733 | } |
9e0c209e | 3734 | |
a2a8927a | 3735 | impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for Body<'tcx> { |
f9f354fc | 3736 | type Item = BasicBlock; |
17df50a5 | 3737 | type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>; |
f9f354fc XL |
3738 | } |
3739 | ||
a2a8927a | 3740 | impl<'tcx> graph::WithPredecessors for Body<'tcx> { |
f9f354fc XL |
3741 | #[inline] |
3742 | fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter { | |
17df50a5 | 3743 | self.predecessors()[node].iter().copied() |
f9f354fc XL |
3744 | } |
3745 | } | |
3746 | ||
ba9703b0 XL |
3747 | /// `Location` represents the position of the start of the statement; or, if |
3748 | /// `statement_index` equals the number of statements, then the start of the | |
3749 | /// terminator. | |
532ac7d7 | 3750 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)] |
9e0c209e | 3751 | pub struct Location { |
e1599b0c | 3752 | /// The block that the location is within. |
9e0c209e SL |
3753 | pub block: BasicBlock, |
3754 | ||
9e0c209e SL |
3755 | pub statement_index: usize, |
3756 | } | |
3757 | ||
3758 | impl fmt::Debug for Location { | |
0bf4aa26 | 3759 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
9e0c209e SL |
3760 | write!(fmt, "{:?}[{}]", self.block, self.statement_index) |
3761 | } | |
3762 | } | |
3763 | ||
3764 | impl Location { | |
416331ca | 3765 | pub const START: Location = Location { block: START_BLOCK, statement_index: 0 }; |
83c7162d | 3766 | |
abe05a73 XL |
3767 | /// Returns the location immediately after this one within the enclosing block. |
3768 | /// | |
3769 | /// Note that if this location represents a terminator, then the | |
3770 | /// resulting location would be out of bounds and invalid. | |
3771 | pub fn successor_within_block(&self) -> Location { | |
416331ca | 3772 | Location { block: self.block, statement_index: self.statement_index + 1 } |
abe05a73 XL |
3773 | } |
3774 | ||
a1dfa0c6 | 3775 | /// Returns `true` if `other` is earlier in the control flow graph than `self`. |
f9f354fc | 3776 | pub fn is_predecessor_of<'tcx>(&self, other: Location, body: &Body<'tcx>) -> bool { |
a1dfa0c6 XL |
3777 | // If we are in the same block as the other location and are an earlier statement |
3778 | // then we are a predecessor of `other`. | |
3779 | if self.block == other.block && self.statement_index < other.statement_index { | |
3780 | return true; | |
3781 | } | |
3782 | ||
f9f354fc XL |
3783 | let predecessors = body.predecessors(); |
3784 | ||
a1dfa0c6 | 3785 | // If we're in another block, then we want to check that block is a predecessor of `other`. |
f9f354fc | 3786 | let mut queue: Vec<BasicBlock> = predecessors[other.block].to_vec(); |
a1dfa0c6 XL |
3787 | let mut visited = FxHashSet::default(); |
3788 | ||
3789 | while let Some(block) = queue.pop() { | |
5099ac24 | 3790 | // If we haven't visited this block before, then make sure we visit its predecessors. |
a1dfa0c6 | 3791 | if visited.insert(block) { |
f9f354fc | 3792 | queue.extend(predecessors[block].iter().cloned()); |
a1dfa0c6 XL |
3793 | } else { |
3794 | continue; | |
3795 | } | |
3796 | ||
3797 | // If we found the block that `self` is in, then we are a predecessor of `other` (since | |
3798 | // we found that block by looking at the predecessors of `other`). | |
3799 | if self.block == block { | |
3800 | return true; | |
3801 | } | |
3802 | } | |
3803 | ||
3804 | false | |
3805 | } | |
3806 | ||
83c7162d | 3807 | pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool { |
9e0c209e SL |
3808 | if self.block == other.block { |
3809 | self.statement_index <= other.statement_index | |
3810 | } else { | |
3811 | dominators.is_dominated_by(other.block, self.block) | |
3812 | } | |
3813 | } | |
3814 | } |