]>
Commit | Line | Data |
---|---|---|
fc512014 XL |
1 | //! # The MIR Visitor |
2 | //! | |
3 | //! ## Overview | |
4 | //! | |
5 | //! There are two visitors, one for immutable and one for mutable references, | |
6 | //! but both are generated by the following macro. The code is written according | |
7 | //! to the following conventions: | |
8 | //! | |
9 | //! - introduce a `visit_foo` and a `super_foo` method for every MIR type | |
10 | //! - `visit_foo`, by default, calls `super_foo` | |
11 | //! - `super_foo`, by default, destructures the `foo` and calls `visit_foo` | |
12 | //! | |
13 | //! This allows you as a user to override `visit_foo` for types are | |
14 | //! interested in, and invoke (within that method) call | |
15 | //! `self.super_foo` to get the default behavior. Just as in an OO | |
16 | //! language, you should never call `super` methods ordinarily except | |
17 | //! in that circumstance. | |
18 | //! | |
19 | //! For the most part, we do not destructure things external to the | |
20 | //! MIR, e.g., types, spans, etc, but simply visit them and stop. This | |
21 | //! avoids duplication with other visitors like `TypeFoldable`. | |
22 | //! | |
23 | //! ## Updating | |
24 | //! | |
25 | //! The code is written in a very deliberate style intended to minimize | |
26 | //! the chance of things being overlooked. You'll notice that we always | |
27 | //! use pattern matching to reference fields and we ensure that all | |
28 | //! matches are exhaustive. | |
29 | //! | |
30 | //! For example, the `super_basic_block_data` method begins like this: | |
31 | //! | |
32 | //! ```rust | |
33 | //! fn super_basic_block_data(&mut self, | |
34 | //! block: BasicBlock, | |
35 | //! data: & $($mutability)? BasicBlockData<'tcx>) { | |
36 | //! let BasicBlockData { | |
37 | //! statements, | |
38 | //! terminator, | |
39 | //! is_cleanup: _ | |
40 | //! } = *data; | |
41 | //! | |
42 | //! for statement in statements { | |
43 | //! self.visit_statement(block, statement); | |
44 | //! } | |
45 | //! | |
46 | //! ... | |
47 | //! } | |
48 | //! ``` | |
49 | //! | |
50 | //! Here we used `let BasicBlockData { <fields> } = *data` deliberately, | |
51 | //! rather than writing `data.statements` in the body. This is because if one | |
52 | //! adds a new field to `BasicBlockData`, one will be forced to revise this code, | |
53 | //! and hence one will (hopefully) invoke the correct visit methods (if any). | |
54 | //! | |
55 | //! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. | |
56 | //! That means you never write `..` to skip over fields, nor do you write `_` | |
57 | //! to skip over variants in a `match`. | |
58 | //! | |
59 | //! The only place that `_` is acceptable is to match a field (or | |
60 | //! variant argument) that does not require visiting, as in | |
61 | //! `is_cleanup` above. | |
62 | ||
dfeec247 | 63 | use crate::mir::*; |
532ac7d7 | 64 | use crate::ty::subst::SubstsRef; |
e74abb32 | 65 | use crate::ty::{CanonicalUserTypeAnnotation, Ty}; |
dfeec247 | 66 | use rustc_span::Span; |
92a42be0 | 67 | |
9cc50fc6 | 68 | macro_rules! make_mir_visitor { |
9fa01778 | 69 | ($visitor_trait_name:ident, $($mutability:ident)?) => { |
9cc50fc6 SL |
70 | pub trait $visitor_trait_name<'tcx> { |
71 | // Override these, and call `self.super_xxx` to revert back to the | |
72 | // default behavior. | |
92a42be0 | 73 | |
60c5eb7d XL |
74 | fn visit_body( |
75 | &mut self, | |
f9f354fc | 76 | body: &$($mutability)? Body<'tcx>, |
60c5eb7d | 77 | ) { |
dc9dc135 | 78 | self.super_body(body); |
9cc50fc6 | 79 | } |
92a42be0 | 80 | |
9cc50fc6 SL |
81 | fn visit_basic_block_data(&mut self, |
82 | block: BasicBlock, | |
9fa01778 | 83 | data: & $($mutability)? BasicBlockData<'tcx>) { |
9cc50fc6 SL |
84 | self.super_basic_block_data(block, data); |
85 | } | |
92a42be0 | 86 | |
94b46f34 | 87 | fn visit_source_scope_data(&mut self, |
29967ef6 | 88 | scope_data: & $($mutability)? SourceScopeData<'tcx>) { |
94b46f34 | 89 | self.super_source_scope_data(scope_data); |
54a0048b SL |
90 | } |
91 | ||
9cc50fc6 | 92 | fn visit_statement(&mut self, |
9fa01778 | 93 | statement: & $($mutability)? Statement<'tcx>, |
9e0c209e | 94 | location: Location) { |
48663c56 | 95 | self.super_statement(statement, location); |
92a42be0 | 96 | } |
9cc50fc6 SL |
97 | |
98 | fn visit_assign(&mut self, | |
9fa01778 XL |
99 | place: & $($mutability)? Place<'tcx>, |
100 | rvalue: & $($mutability)? Rvalue<'tcx>, | |
9e0c209e | 101 | location: Location) { |
48663c56 | 102 | self.super_assign(place, rvalue, location); |
92a42be0 | 103 | } |
92a42be0 | 104 | |
9cc50fc6 | 105 | fn visit_terminator(&mut self, |
9fa01778 | 106 | terminator: & $($mutability)? Terminator<'tcx>, |
9e0c209e | 107 | location: Location) { |
48663c56 | 108 | self.super_terminator(terminator, location); |
9cc50fc6 | 109 | } |
92a42be0 | 110 | |
3157f602 | 111 | fn visit_assert_message(&mut self, |
9fa01778 | 112 | msg: & $($mutability)? AssertMessage<'tcx>, |
9e0c209e SL |
113 | location: Location) { |
114 | self.super_assert_message(msg, location); | |
3157f602 XL |
115 | } |
116 | ||
9cc50fc6 | 117 | fn visit_rvalue(&mut self, |
9fa01778 | 118 | rvalue: & $($mutability)? Rvalue<'tcx>, |
9e0c209e SL |
119 | location: Location) { |
120 | self.super_rvalue(rvalue, location); | |
92a42be0 SL |
121 | } |
122 | ||
9cc50fc6 | 123 | fn visit_operand(&mut self, |
9fa01778 | 124 | operand: & $($mutability)? Operand<'tcx>, |
9e0c209e SL |
125 | location: Location) { |
126 | self.super_operand(operand, location); | |
92a42be0 SL |
127 | } |
128 | ||
b7449926 | 129 | fn visit_ascribe_user_ty(&mut self, |
9fa01778 XL |
130 | place: & $($mutability)? Place<'tcx>, |
131 | variance: & $($mutability)? ty::Variance, | |
532ac7d7 | 132 | user_ty: & $($mutability)? UserTypeProjection, |
b7449926 | 133 | location: Location) { |
0bf4aa26 | 134 | self.super_ascribe_user_ty(place, variance, user_ty, location); |
0531ce1d XL |
135 | } |
136 | ||
3dfed10e XL |
137 | fn visit_coverage(&mut self, |
138 | coverage: & $($mutability)? Coverage, | |
139 | location: Location) { | |
140 | self.super_coverage(coverage, location); | |
141 | } | |
142 | ||
a1dfa0c6 | 143 | fn visit_retag(&mut self, |
9fa01778 XL |
144 | kind: & $($mutability)? RetagKind, |
145 | place: & $($mutability)? Place<'tcx>, | |
a1dfa0c6 | 146 | location: Location) { |
0731742a | 147 | self.super_retag(kind, place, location); |
a1dfa0c6 XL |
148 | } |
149 | ||
ff7c6d11 | 150 | fn visit_place(&mut self, |
9fa01778 | 151 | place: & $($mutability)? Place<'tcx>, |
48663c56 | 152 | context: PlaceContext, |
9e0c209e | 153 | location: Location) { |
ff7c6d11 | 154 | self.super_place(place, context, location); |
92a42be0 SL |
155 | } |
156 | ||
e74abb32 | 157 | visit_place_fns!($($mutability)?); |
54a0048b | 158 | |
9cc50fc6 | 159 | fn visit_constant(&mut self, |
9fa01778 | 160 | constant: & $($mutability)? Constant<'tcx>, |
9e0c209e SL |
161 | location: Location) { |
162 | self.super_constant(constant, location); | |
92a42be0 SL |
163 | } |
164 | ||
9cc50fc6 | 165 | fn visit_span(&mut self, |
9fa01778 | 166 | span: & $($mutability)? Span) { |
9cc50fc6 | 167 | self.super_span(span); |
92a42be0 SL |
168 | } |
169 | ||
3157f602 | 170 | fn visit_source_info(&mut self, |
9fa01778 | 171 | source_info: & $($mutability)? SourceInfo) { |
3157f602 XL |
172 | self.super_source_info(source_info); |
173 | } | |
174 | ||
54a0048b | 175 | fn visit_ty(&mut self, |
48663c56 | 176 | ty: $(& $mutability)? Ty<'tcx>, |
abe05a73 | 177 | _: TyContext) { |
54a0048b SL |
178 | self.super_ty(ty); |
179 | } | |
180 | ||
0bf4aa26 XL |
181 | fn visit_user_type_projection( |
182 | &mut self, | |
532ac7d7 | 183 | ty: & $($mutability)? UserTypeProjection, |
0bf4aa26 XL |
184 | ) { |
185 | self.super_user_type_projection(ty); | |
186 | } | |
187 | ||
188 | fn visit_user_type_annotation( | |
189 | &mut self, | |
0731742a | 190 | index: UserTypeAnnotationIndex, |
9fa01778 | 191 | ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>, |
0bf4aa26 | 192 | ) { |
0731742a | 193 | self.super_user_type_annotation(index, ty); |
b7449926 XL |
194 | } |
195 | ||
ea8adc8c | 196 | fn visit_region(&mut self, |
9fa01778 | 197 | region: & $($mutability)? ty::Region<'tcx>, |
ea8adc8c XL |
198 | _: Location) { |
199 | self.super_region(region); | |
200 | } | |
201 | ||
202 | fn visit_const(&mut self, | |
532ac7d7 | 203 | constant: & $($mutability)? &'tcx ty::Const<'tcx>, |
ea8adc8c XL |
204 | _: Location) { |
205 | self.super_const(constant); | |
206 | } | |
207 | ||
54a0048b | 208 | fn visit_substs(&mut self, |
532ac7d7 | 209 | substs: & $($mutability)? SubstsRef<'tcx>, |
3b2f2976 | 210 | _: Location) { |
54a0048b SL |
211 | self.super_substs(substs); |
212 | } | |
213 | ||
c30ab7b3 | 214 | fn visit_local_decl(&mut self, |
abe05a73 | 215 | local: Local, |
9fa01778 | 216 | local_decl: & $($mutability)? LocalDecl<'tcx>) { |
abe05a73 | 217 | self.super_local_decl(local, local_decl); |
54a0048b SL |
218 | } |
219 | ||
60c5eb7d XL |
220 | fn visit_var_debug_info(&mut self, |
221 | var_debug_info: & $($mutability)* VarDebugInfo<'tcx>) { | |
222 | self.super_var_debug_info(var_debug_info); | |
223 | } | |
224 | ||
ea8adc8c | 225 | fn visit_local(&mut self, |
9fa01778 | 226 | _local: & $($mutability)? Local, |
48663c56 | 227 | _context: PlaceContext, |
ea8adc8c XL |
228 | _location: Location) { |
229 | } | |
230 | ||
94b46f34 | 231 | fn visit_source_scope(&mut self, |
9fa01778 | 232 | scope: & $($mutability)? SourceScope) { |
94b46f34 | 233 | self.super_source_scope(scope); |
54a0048b SL |
234 | } |
235 | ||
9cc50fc6 | 236 | // The `super_xxx` methods comprise the default behavior and are |
7453a54e | 237 | // not meant to be overridden. |
9cc50fc6 | 238 | |
60c5eb7d XL |
239 | fn super_body( |
240 | &mut self, | |
f9f354fc | 241 | body: &$($mutability)? Body<'tcx>, |
60c5eb7d XL |
242 | ) { |
243 | let span = body.span; | |
6a06907d XL |
244 | if let Some(gen) = &$($mutability)? body.generator { |
245 | if let Some(yield_ty) = &$($mutability)? gen.yield_ty { | |
246 | self.visit_ty( | |
247 | yield_ty, | |
248 | TyContext::YieldTy(SourceInfo::outermost(span)) | |
249 | ); | |
250 | } | |
2c00a5a8 XL |
251 | } |
252 | ||
3b2f2976 | 253 | // for best performance, we want to use an iterator rather |
dc9dc135 | 254 | // than a for-loop, to avoid calling `body::Body::invalidate` for |
3b2f2976 XL |
255 | // each basic block. |
256 | macro_rules! basic_blocks { | |
dc9dc135 XL |
257 | (mut) => (body.basic_blocks_mut().iter_enumerated_mut()); |
258 | () => (body.basic_blocks().iter_enumerated()); | |
fc512014 | 259 | } |
9fa01778 | 260 | for (bb, data) in basic_blocks!($($mutability)?) { |
3b2f2976 | 261 | self.visit_basic_block_data(bb, data); |
9cc50fc6 | 262 | } |
54a0048b | 263 | |
dc9dc135 | 264 | for scope in &$($mutability)? body.source_scopes { |
94b46f34 | 265 | self.visit_source_scope_data(scope); |
54a0048b SL |
266 | } |
267 | ||
f9f354fc XL |
268 | self.visit_ty( |
269 | &$($mutability)? body.return_ty(), | |
270 | TyContext::ReturnTy(SourceInfo::outermost(body.span)) | |
271 | ); | |
54a0048b | 272 | |
dc9dc135 XL |
273 | for local in body.local_decls.indices() { |
274 | self.visit_local_decl(local, & $($mutability)? body.local_decls[local]); | |
54a0048b SL |
275 | } |
276 | ||
9fa01778 | 277 | macro_rules! type_annotations { |
dc9dc135 XL |
278 | (mut) => (body.user_type_annotations.iter_enumerated_mut()); |
279 | () => (body.user_type_annotations.iter_enumerated()); | |
fc512014 | 280 | } |
9fa01778 XL |
281 | |
282 | for (index, annotation) in type_annotations!($($mutability)?) { | |
0731742a XL |
283 | self.visit_user_type_annotation( |
284 | index, annotation | |
285 | ); | |
0731742a XL |
286 | } |
287 | ||
60c5eb7d XL |
288 | for var_debug_info in &$($mutability)? body.var_debug_info { |
289 | self.visit_var_debug_info(var_debug_info); | |
290 | } | |
291 | ||
dc9dc135 | 292 | self.visit_span(&$($mutability)? body.span); |
f9f354fc XL |
293 | |
294 | for const_ in &$($mutability)? body.required_consts { | |
295 | let location = START_BLOCK.start_location(); | |
296 | self.visit_constant(const_, location); | |
297 | } | |
92a42be0 SL |
298 | } |
299 | ||
9cc50fc6 SL |
300 | fn super_basic_block_data(&mut self, |
301 | block: BasicBlock, | |
9fa01778 | 302 | data: & $($mutability)? BasicBlockData<'tcx>) { |
54a0048b | 303 | let BasicBlockData { |
9fa01778 XL |
304 | statements, |
305 | terminator, | |
54a0048b | 306 | is_cleanup: _ |
9fa01778 | 307 | } = data; |
54a0048b | 308 | |
9e0c209e | 309 | let mut index = 0; |
54a0048b | 310 | for statement in statements { |
5869c6ff | 311 | let location = Location { block, statement_index: index }; |
48663c56 | 312 | self.visit_statement(statement, location); |
9e0c209e | 313 | index += 1; |
9cc50fc6 SL |
314 | } |
315 | ||
9fa01778 | 316 | if let Some(terminator) = terminator { |
5869c6ff | 317 | let location = Location { block, statement_index: index }; |
48663c56 | 318 | self.visit_terminator(terminator, location); |
9cc50fc6 | 319 | } |
92a42be0 SL |
320 | } |
321 | ||
29967ef6 XL |
322 | fn super_source_scope_data( |
323 | &mut self, | |
324 | scope_data: & $($mutability)? SourceScopeData<'tcx>, | |
325 | ) { | |
94b46f34 | 326 | let SourceScopeData { |
9fa01778 XL |
327 | span, |
328 | parent_scope, | |
29967ef6 XL |
329 | inlined, |
330 | inlined_parent_scope, | |
60c5eb7d | 331 | local_data: _, |
9fa01778 | 332 | } = scope_data; |
54a0048b | 333 | |
a7813a04 | 334 | self.visit_span(span); |
9fa01778 | 335 | if let Some(parent_scope) = parent_scope { |
94b46f34 | 336 | self.visit_source_scope(parent_scope); |
54a0048b | 337 | } |
29967ef6 XL |
338 | if let Some((callee, callsite_span)) = inlined { |
339 | let location = START_BLOCK.start_location(); | |
340 | ||
341 | self.visit_span(callsite_span); | |
342 | ||
343 | let ty::Instance { def: callee_def, substs: callee_substs } = callee; | |
344 | match callee_def { | |
345 | ty::InstanceDef::Item(_def_id) => {} | |
346 | ||
347 | ty::InstanceDef::Intrinsic(_def_id) | | |
348 | ty::InstanceDef::VtableShim(_def_id) | | |
349 | ty::InstanceDef::ReifyShim(_def_id) | | |
350 | ty::InstanceDef::Virtual(_def_id, _) | | |
351 | ty::InstanceDef::ClosureOnceShim { call_once: _def_id } | | |
352 | ty::InstanceDef::DropGlue(_def_id, None) => {} | |
353 | ||
354 | ty::InstanceDef::FnPtrShim(_def_id, ty) | | |
355 | ty::InstanceDef::DropGlue(_def_id, Some(ty)) | | |
356 | ty::InstanceDef::CloneShim(_def_id, ty) => { | |
357 | // FIXME(eddyb) use a better `TyContext` here. | |
358 | self.visit_ty(ty, TyContext::Location(location)); | |
359 | } | |
360 | } | |
361 | self.visit_substs(callee_substs, location); | |
362 | } | |
363 | if let Some(inlined_parent_scope) = inlined_parent_scope { | |
364 | self.visit_source_scope(inlined_parent_scope); | |
365 | } | |
54a0048b SL |
366 | } |
367 | ||
9cc50fc6 | 368 | fn super_statement(&mut self, |
9fa01778 | 369 | statement: & $($mutability)? Statement<'tcx>, |
9e0c209e | 370 | location: Location) { |
54a0048b | 371 | let Statement { |
9fa01778 XL |
372 | source_info, |
373 | kind, | |
374 | } = statement; | |
54a0048b | 375 | |
3157f602 | 376 | self.visit_source_info(source_info); |
9fa01778 | 377 | match kind { |
e1599b0c XL |
378 | StatementKind::Assign( |
379 | box(ref $($mutability)? place, ref $($mutability)? rvalue) | |
380 | ) => { | |
48663c56 | 381 | self.visit_assign(place, rvalue, location); |
9cc50fc6 | 382 | } |
9fa01778 | 383 | StatementKind::FakeRead(_, place) => { |
13cf67c4 XL |
384 | self.visit_place( |
385 | place, | |
386 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), | |
387 | location | |
388 | ); | |
94b46f34 | 389 | } |
9fa01778 | 390 | StatementKind::SetDiscriminant { place, .. } => { |
13cf67c4 XL |
391 | self.visit_place( |
392 | place, | |
393 | PlaceContext::MutatingUse(MutatingUseContext::Store), | |
394 | location | |
395 | ); | |
5bcae85e | 396 | } |
9fa01778 | 397 | StatementKind::StorageLive(local) => { |
13cf67c4 XL |
398 | self.visit_local( |
399 | local, | |
400 | PlaceContext::NonUse(NonUseContext::StorageLive), | |
401 | location | |
402 | ); | |
5bcae85e | 403 | } |
9fa01778 | 404 | StatementKind::StorageDead(local) => { |
13cf67c4 XL |
405 | self.visit_local( |
406 | local, | |
407 | PlaceContext::NonUse(NonUseContext::StorageDead), | |
408 | location | |
409 | ); | |
5bcae85e | 410 | } |
ba9703b0 | 411 | StatementKind::LlvmInlineAsm(asm) => { |
532ac7d7 | 412 | for output in & $($mutability)? asm.outputs[..] { |
13cf67c4 XL |
413 | self.visit_place( |
414 | output, | |
415 | PlaceContext::MutatingUse(MutatingUseContext::AsmOutput), | |
416 | location | |
417 | ); | |
8bb4bdeb | 418 | } |
532ac7d7 | 419 | for (span, input) in & $($mutability)? asm.inputs[..] { |
a1dfa0c6 | 420 | self.visit_span(span); |
8bb4bdeb XL |
421 | self.visit_operand(input, location); |
422 | } | |
423 | } | |
9fa01778 | 424 | StatementKind::Retag(kind, place) => { |
0731742a | 425 | self.visit_retag(kind, place, location); |
a1dfa0c6 | 426 | } |
e1599b0c XL |
427 | StatementKind::AscribeUserType( |
428 | box(ref $($mutability)? place, ref $($mutability)? user_ty), | |
429 | variance | |
430 | ) => { | |
0bf4aa26 | 431 | self.visit_ascribe_user_ty(place, variance, user_ty, location); |
0531ce1d | 432 | } |
3dfed10e XL |
433 | StatementKind::Coverage(coverage) => { |
434 | self.visit_coverage( | |
435 | coverage, | |
436 | location | |
437 | ) | |
438 | } | |
6a06907d XL |
439 | StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{ |
440 | ref $($mutability)? src, | |
441 | ref $($mutability)? dst, | |
442 | ref $($mutability)? count, | |
443 | }) => { | |
444 | self.visit_operand(src, location); | |
445 | self.visit_operand(dst, location); | |
446 | self.visit_operand(count, location) | |
447 | } | |
9e0c209e | 448 | StatementKind::Nop => {} |
9cc50fc6 | 449 | } |
92a42be0 SL |
450 | } |
451 | ||
9cc50fc6 | 452 | fn super_assign(&mut self, |
9fa01778 XL |
453 | place: &$($mutability)? Place<'tcx>, |
454 | rvalue: &$($mutability)? Rvalue<'tcx>, | |
9e0c209e | 455 | location: Location) { |
13cf67c4 XL |
456 | self.visit_place( |
457 | place, | |
458 | PlaceContext::MutatingUse(MutatingUseContext::Store), | |
459 | location | |
460 | ); | |
9e0c209e | 461 | self.visit_rvalue(rvalue, location); |
92a42be0 SL |
462 | } |
463 | ||
9cc50fc6 | 464 | fn super_terminator(&mut self, |
9fa01778 | 465 | terminator: &$($mutability)? Terminator<'tcx>, |
9e0c209e | 466 | location: Location) { |
9fa01778 | 467 | let Terminator { source_info, kind } = terminator; |
54a0048b | 468 | |
3157f602 | 469 | self.visit_source_info(source_info); |
9fa01778 | 470 | match kind { |
48663c56 XL |
471 | TerminatorKind::Goto { .. } | |
472 | TerminatorKind::Resume | | |
473 | TerminatorKind::Abort | | |
48663c56 XL |
474 | TerminatorKind::GeneratorDrop | |
475 | TerminatorKind::Unreachable | | |
f035d41b | 476 | TerminatorKind::FalseEdge { .. } | |
48663c56 | 477 | TerminatorKind::FalseUnwind { .. } => { |
9cc50fc6 SL |
478 | } |
479 | ||
f9f354fc XL |
480 | TerminatorKind::Return => { |
481 | // `return` logically moves from the return place `_0`. Note that the place | |
482 | // cannot be changed by any visitor, though. | |
483 | let $($mutability)? local = RETURN_PLACE; | |
484 | self.visit_local( | |
485 | & $($mutability)? local, | |
486 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move), | |
f035d41b | 487 | location, |
f9f354fc XL |
488 | ); |
489 | ||
490 | assert_eq!( | |
491 | local, | |
492 | RETURN_PLACE, | |
493 | "`MutVisitor` tried to mutate return place of `return` terminator" | |
494 | ); | |
495 | } | |
496 | ||
9fa01778 XL |
497 | TerminatorKind::SwitchInt { |
498 | discr, | |
499 | switch_ty, | |
48663c56 | 500 | targets: _ |
9fa01778 | 501 | } => { |
f035d41b XL |
502 | self.visit_operand(discr, location); |
503 | self.visit_ty(switch_ty, TyContext::Location(location)); | |
9cc50fc6 SL |
504 | } |
505 | ||
9fa01778 | 506 | TerminatorKind::Drop { |
f035d41b | 507 | place, |
48663c56 XL |
508 | target: _, |
509 | unwind: _, | |
9fa01778 | 510 | } => { |
13cf67c4 | 511 | self.visit_place( |
f035d41b | 512 | place, |
13cf67c4 | 513 | PlaceContext::MutatingUse(MutatingUseContext::Drop), |
f035d41b | 514 | location |
13cf67c4 | 515 | ); |
3157f602 XL |
516 | } |
517 | ||
9fa01778 | 518 | TerminatorKind::DropAndReplace { |
f035d41b | 519 | place, |
9fa01778 | 520 | value, |
48663c56 XL |
521 | target: _, |
522 | unwind: _, | |
9fa01778 | 523 | } => { |
13cf67c4 | 524 | self.visit_place( |
f035d41b | 525 | place, |
13cf67c4 | 526 | PlaceContext::MutatingUse(MutatingUseContext::Drop), |
f035d41b | 527 | location |
13cf67c4 | 528 | ); |
f035d41b | 529 | self.visit_operand(value, location); |
7453a54e SL |
530 | } |
531 | ||
9fa01778 XL |
532 | TerminatorKind::Call { |
533 | func, | |
534 | args, | |
535 | destination, | |
48663c56 | 536 | cleanup: _, |
9fa01778 | 537 | from_hir_call: _, |
f035d41b | 538 | fn_span: _ |
9fa01778 | 539 | } => { |
f035d41b | 540 | self.visit_operand(func, location); |
9cc50fc6 | 541 | for arg in args { |
f035d41b | 542 | self.visit_operand(arg, location); |
9cc50fc6 | 543 | } |
48663c56 | 544 | if let Some((destination, _)) = destination { |
13cf67c4 XL |
545 | self.visit_place( |
546 | destination, | |
547 | PlaceContext::MutatingUse(MutatingUseContext::Call), | |
f035d41b | 548 | location |
13cf67c4 | 549 | ); |
9cc50fc6 SL |
550 | } |
551 | } | |
3157f602 | 552 | |
9fa01778 XL |
553 | TerminatorKind::Assert { |
554 | cond, | |
555 | expected: _, | |
556 | msg, | |
48663c56 XL |
557 | target: _, |
558 | cleanup: _, | |
9fa01778 | 559 | } => { |
f035d41b XL |
560 | self.visit_operand(cond, location); |
561 | self.visit_assert_message(msg, location); | |
3157f602 | 562 | } |
ea8adc8c | 563 | |
9fa01778 XL |
564 | TerminatorKind::Yield { |
565 | value, | |
48663c56 | 566 | resume: _, |
74b04a01 | 567 | resume_arg, |
48663c56 | 568 | drop: _, |
9fa01778 | 569 | } => { |
f035d41b | 570 | self.visit_operand(value, location); |
74b04a01 XL |
571 | self.visit_place( |
572 | resume_arg, | |
f9f354fc | 573 | PlaceContext::MutatingUse(MutatingUseContext::Yield), |
f035d41b | 574 | location, |
74b04a01 | 575 | ); |
ea8adc8c XL |
576 | } |
577 | ||
f9f354fc XL |
578 | TerminatorKind::InlineAsm { |
579 | template: _, | |
580 | operands, | |
581 | options: _, | |
582 | line_spans: _, | |
583 | destination: _, | |
584 | } => { | |
585 | for op in operands { | |
586 | match op { | |
587 | InlineAsmOperand::In { value, .. } | |
588 | | InlineAsmOperand::Const { value } => { | |
f035d41b | 589 | self.visit_operand(value, location); |
f9f354fc XL |
590 | } |
591 | InlineAsmOperand::Out { place, .. } => { | |
592 | if let Some(place) = place { | |
593 | self.visit_place( | |
594 | place, | |
595 | PlaceContext::MutatingUse(MutatingUseContext::Store), | |
f035d41b | 596 | location, |
f9f354fc XL |
597 | ); |
598 | } | |
599 | } | |
600 | InlineAsmOperand::InOut { in_value, out_place, .. } => { | |
f035d41b | 601 | self.visit_operand(in_value, location); |
f9f354fc XL |
602 | if let Some(out_place) = out_place { |
603 | self.visit_place( | |
604 | out_place, | |
605 | PlaceContext::MutatingUse(MutatingUseContext::Store), | |
f035d41b | 606 | location, |
f9f354fc XL |
607 | ); |
608 | } | |
609 | } | |
f035d41b XL |
610 | InlineAsmOperand::SymFn { value } => { |
611 | self.visit_constant(value, location); | |
f9f354fc | 612 | } |
f035d41b | 613 | InlineAsmOperand::SymStatic { def_id: _ } => {} |
f9f354fc XL |
614 | } |
615 | } | |
616 | } | |
3157f602 XL |
617 | } |
618 | } | |
619 | ||
620 | fn super_assert_message(&mut self, | |
9fa01778 | 621 | msg: & $($mutability)? AssertMessage<'tcx>, |
9e0c209e | 622 | location: Location) { |
74b04a01 | 623 | use crate::mir::AssertKind::*; |
416331ca XL |
624 | match msg { |
625 | BoundsCheck { len, index } => { | |
626 | self.visit_operand(len, location); | |
627 | self.visit_operand(index, location); | |
628 | } | |
f035d41b XL |
629 | Overflow(_, l, r) => { |
630 | self.visit_operand(l, location); | |
631 | self.visit_operand(r, location); | |
632 | } | |
633 | OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { | |
634 | self.visit_operand(op, location); | |
635 | } | |
60c5eb7d | 636 | ResumedAfterReturn(_) | ResumedAfterPanic(_) => { |
416331ca XL |
637 | // Nothing to visit |
638 | } | |
9cc50fc6 | 639 | } |
92a42be0 SL |
640 | } |
641 | ||
9cc50fc6 | 642 | fn super_rvalue(&mut self, |
9fa01778 | 643 | rvalue: & $($mutability)? Rvalue<'tcx>, |
9e0c209e | 644 | location: Location) { |
9fa01778 XL |
645 | match rvalue { |
646 | Rvalue::Use(operand) => { | |
9e0c209e | 647 | self.visit_operand(operand, location); |
9cc50fc6 SL |
648 | } |
649 | ||
9fa01778 | 650 | Rvalue::Repeat(value, _) => { |
9e0c209e | 651 | self.visit_operand(value, location); |
9cc50fc6 SL |
652 | } |
653 | ||
f9f354fc XL |
654 | Rvalue::ThreadLocalRef(_) => {} |
655 | ||
9fa01778 | 656 | Rvalue::Ref(r, bk, path) => { |
ea8adc8c | 657 | self.visit_region(r, location); |
13cf67c4 XL |
658 | let ctx = match bk { |
659 | BorrowKind::Shared => PlaceContext::NonMutatingUse( | |
48663c56 | 660 | NonMutatingUseContext::SharedBorrow |
13cf67c4 XL |
661 | ), |
662 | BorrowKind::Shallow => PlaceContext::NonMutatingUse( | |
48663c56 | 663 | NonMutatingUseContext::ShallowBorrow |
13cf67c4 XL |
664 | ), |
665 | BorrowKind::Unique => PlaceContext::NonMutatingUse( | |
48663c56 | 666 | NonMutatingUseContext::UniqueBorrow |
13cf67c4 XL |
667 | ), |
668 | BorrowKind::Mut { .. } => | |
48663c56 | 669 | PlaceContext::MutatingUse(MutatingUseContext::Borrow), |
13cf67c4 XL |
670 | }; |
671 | self.visit_place(path, ctx, location); | |
9cc50fc6 SL |
672 | } |
673 | ||
dfeec247 XL |
674 | Rvalue::AddressOf(m, path) => { |
675 | let ctx = match m { | |
676 | Mutability::Mut => PlaceContext::MutatingUse( | |
677 | MutatingUseContext::AddressOf | |
678 | ), | |
679 | Mutability::Not => PlaceContext::NonMutatingUse( | |
680 | NonMutatingUseContext::AddressOf | |
681 | ), | |
682 | }; | |
683 | self.visit_place(path, ctx, location); | |
684 | } | |
685 | ||
9fa01778 | 686 | Rvalue::Len(path) => { |
13cf67c4 XL |
687 | self.visit_place( |
688 | path, | |
689 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), | |
690 | location | |
691 | ); | |
9cc50fc6 SL |
692 | } |
693 | ||
9fa01778 | 694 | Rvalue::Cast(_cast_kind, operand, ty) => { |
9e0c209e | 695 | self.visit_operand(operand, location); |
abe05a73 | 696 | self.visit_ty(ty, TyContext::Location(location)); |
9cc50fc6 SL |
697 | } |
698 | ||
6a06907d XL |
699 | Rvalue::BinaryOp(_bin_op, box(lhs, rhs)) |
700 | | Rvalue::CheckedBinaryOp(_bin_op, box(lhs, rhs)) => { | |
9e0c209e SL |
701 | self.visit_operand(lhs, location); |
702 | self.visit_operand(rhs, location); | |
9cc50fc6 SL |
703 | } |
704 | ||
9fa01778 | 705 | Rvalue::UnaryOp(_un_op, op) => { |
9e0c209e | 706 | self.visit_operand(op, location); |
9cc50fc6 SL |
707 | } |
708 | ||
9fa01778 | 709 | Rvalue::Discriminant(place) => { |
13cf67c4 XL |
710 | self.visit_place( |
711 | place, | |
712 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), | |
713 | location | |
714 | ); | |
8bb4bdeb XL |
715 | } |
716 | ||
9fa01778 | 717 | Rvalue::NullaryOp(_op, ty) => { |
abe05a73 | 718 | self.visit_ty(ty, TyContext::Location(location)); |
9cc50fc6 SL |
719 | } |
720 | ||
9fa01778 XL |
721 | Rvalue::Aggregate(kind, operands) => { |
722 | let kind = &$($mutability)? **kind; | |
723 | match kind { | |
724 | AggregateKind::Array(ty) => { | |
abe05a73 | 725 | self.visit_ty(ty, TyContext::Location(location)); |
54a0048b SL |
726 | } |
727 | AggregateKind::Tuple => { | |
728 | } | |
9fa01778 XL |
729 | AggregateKind::Adt( |
730 | _adt_def, | |
731 | _variant_index, | |
732 | substs, | |
733 | _user_substs, | |
734 | _active_field_index | |
735 | ) => { | |
3b2f2976 | 736 | self.visit_substs(substs, location); |
54a0048b | 737 | } |
9fa01778 | 738 | AggregateKind::Closure( |
48663c56 | 739 | _, |
9fa01778 XL |
740 | closure_substs |
741 | ) => { | |
e74abb32 | 742 | self.visit_substs(closure_substs, location); |
9cc50fc6 | 743 | } |
9fa01778 | 744 | AggregateKind::Generator( |
48663c56 | 745 | _, |
9fa01778 XL |
746 | generator_substs, |
747 | _movability, | |
748 | ) => { | |
e74abb32 | 749 | self.visit_substs(generator_substs, location); |
ea8adc8c | 750 | } |
9cc50fc6 SL |
751 | } |
752 | ||
54a0048b | 753 | for operand in operands { |
9e0c209e | 754 | self.visit_operand(operand, location); |
9cc50fc6 SL |
755 | } |
756 | } | |
9cc50fc6 | 757 | } |
92a42be0 SL |
758 | } |
759 | ||
9cc50fc6 | 760 | fn super_operand(&mut self, |
9fa01778 | 761 | operand: & $($mutability)? Operand<'tcx>, |
9e0c209e | 762 | location: Location) { |
9fa01778 XL |
763 | match operand { |
764 | Operand::Copy(place) => { | |
13cf67c4 XL |
765 | self.visit_place( |
766 | place, | |
767 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), | |
768 | location | |
769 | ); | |
ff7c6d11 | 770 | } |
9fa01778 | 771 | Operand::Move(place) => { |
13cf67c4 XL |
772 | self.visit_place( |
773 | place, | |
774 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move), | |
775 | location | |
776 | ); | |
9cc50fc6 | 777 | } |
9fa01778 | 778 | Operand::Constant(constant) => { |
9e0c209e | 779 | self.visit_constant(constant, location); |
9cc50fc6 | 780 | } |
92a42be0 SL |
781 | } |
782 | } | |
783 | ||
b7449926 | 784 | fn super_ascribe_user_ty(&mut self, |
9fa01778 XL |
785 | place: & $($mutability)? Place<'tcx>, |
786 | _variance: & $($mutability)? ty::Variance, | |
532ac7d7 | 787 | user_ty: & $($mutability)? UserTypeProjection, |
b7449926 | 788 | location: Location) { |
13cf67c4 XL |
789 | self.visit_place( |
790 | place, | |
791 | PlaceContext::NonUse(NonUseContext::AscribeUserTy), | |
792 | location | |
793 | ); | |
0bf4aa26 | 794 | self.visit_user_type_projection(user_ty); |
0531ce1d XL |
795 | } |
796 | ||
3dfed10e | 797 | fn super_coverage(&mut self, |
29967ef6 | 798 | _coverage: & $($mutability)? Coverage, |
3dfed10e XL |
799 | _location: Location) { |
800 | } | |
801 | ||
a1dfa0c6 | 802 | fn super_retag(&mut self, |
9fa01778 XL |
803 | _kind: & $($mutability)? RetagKind, |
804 | place: & $($mutability)? Place<'tcx>, | |
a1dfa0c6 XL |
805 | location: Location) { |
806 | self.visit_place( | |
807 | place, | |
808 | PlaceContext::MutatingUse(MutatingUseContext::Retag), | |
809 | location, | |
810 | ); | |
811 | } | |
812 | ||
c30ab7b3 | 813 | fn super_local_decl(&mut self, |
abe05a73 | 814 | local: Local, |
9fa01778 | 815 | local_decl: & $($mutability)? LocalDecl<'tcx>) { |
c30ab7b3 | 816 | let LocalDecl { |
54a0048b | 817 | mutability: _, |
9fa01778 XL |
818 | ty, |
819 | user_ty, | |
9fa01778 | 820 | source_info, |
ea8adc8c | 821 | internal: _, |
60c5eb7d | 822 | local_info: _, |
0bf4aa26 | 823 | is_block_tail: _, |
9fa01778 | 824 | } = local_decl; |
54a0048b | 825 | |
abe05a73 XL |
826 | self.visit_ty(ty, TyContext::LocalDecl { |
827 | local, | |
828 | source_info: *source_info, | |
829 | }); | |
f9f354fc XL |
830 | if let Some(user_ty) = user_ty { |
831 | for (user_ty, _) in & $($mutability)? user_ty.contents { | |
832 | self.visit_user_type_projection(user_ty); | |
833 | } | |
b7449926 | 834 | } |
cc61c64b | 835 | self.visit_source_info(source_info); |
60c5eb7d XL |
836 | } |
837 | ||
838 | fn super_var_debug_info(&mut self, | |
839 | var_debug_info: & $($mutability)? VarDebugInfo<'tcx>) { | |
840 | let VarDebugInfo { | |
841 | name: _, | |
842 | source_info, | |
fc512014 | 843 | value, |
60c5eb7d XL |
844 | } = var_debug_info; |
845 | ||
846 | self.visit_source_info(source_info); | |
847 | let location = START_BLOCK.start_location(); | |
fc512014 XL |
848 | match value { |
849 | VarDebugInfoContents::Const(c) => self.visit_constant(c, location), | |
850 | VarDebugInfoContents::Place(place) => | |
851 | self.visit_place( | |
852 | place, | |
853 | PlaceContext::NonUse(NonUseContext::VarDebugInfo), | |
854 | location | |
855 | ), | |
856 | } | |
54a0048b SL |
857 | } |
858 | ||
94b46f34 | 859 | fn super_source_scope(&mut self, |
9fa01778 | 860 | _scope: & $($mutability)? SourceScope) { |
54a0048b SL |
861 | } |
862 | ||
9cc50fc6 | 863 | fn super_constant(&mut self, |
9fa01778 | 864 | constant: & $($mutability)? Constant<'tcx>, |
9e0c209e | 865 | location: Location) { |
54a0048b | 866 | let Constant { |
9fa01778 | 867 | span, |
9fa01778 XL |
868 | user_ty, |
869 | literal, | |
870 | } = constant; | |
54a0048b SL |
871 | |
872 | self.visit_span(span); | |
b7449926 | 873 | drop(user_ty); // no visit method for this |
6a06907d XL |
874 | match literal { |
875 | ConstantKind::Ty(ct) => self.visit_const(ct, location), | |
876 | ConstantKind::Val(_, t) => self.visit_ty(t, TyContext::Location(location)), | |
877 | } | |
92a42be0 | 878 | } |
92a42be0 | 879 | |
9fa01778 | 880 | fn super_span(&mut self, _span: & $($mutability)? Span) { |
92a42be0 | 881 | } |
54a0048b | 882 | |
9fa01778 | 883 | fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) { |
3157f602 | 884 | let SourceInfo { |
9fa01778 XL |
885 | span, |
886 | scope, | |
887 | } = source_info; | |
3157f602 XL |
888 | |
889 | self.visit_span(span); | |
94b46f34 | 890 | self.visit_source_scope(scope); |
3157f602 XL |
891 | } |
892 | ||
0bf4aa26 XL |
893 | fn super_user_type_projection( |
894 | &mut self, | |
532ac7d7 | 895 | _ty: & $($mutability)? UserTypeProjection, |
0bf4aa26 | 896 | ) { |
0bf4aa26 XL |
897 | } |
898 | ||
899 | fn super_user_type_annotation( | |
900 | &mut self, | |
0731742a | 901 | _index: UserTypeAnnotationIndex, |
9fa01778 | 902 | ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>, |
0bf4aa26 | 903 | ) { |
9fa01778 XL |
904 | self.visit_span(& $($mutability)? ty.span); |
905 | self.visit_ty(& $($mutability)? ty.inferred_ty, TyContext::UserTy(ty.span)); | |
b7449926 XL |
906 | } |
907 | ||
48663c56 | 908 | fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) { |
54a0048b SL |
909 | } |
910 | ||
9fa01778 | 911 | fn super_region(&mut self, _region: & $($mutability)? ty::Region<'tcx>) { |
ea8adc8c XL |
912 | } |
913 | ||
532ac7d7 | 914 | fn super_const(&mut self, _const: & $($mutability)? &'tcx ty::Const<'tcx>) { |
ea8adc8c XL |
915 | } |
916 | ||
532ac7d7 | 917 | fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) { |
54a0048b SL |
918 | } |
919 | ||
9e0c209e SL |
920 | // Convenience methods |
921 | ||
60c5eb7d XL |
922 | fn visit_location( |
923 | &mut self, | |
f9f354fc | 924 | body: &$($mutability)? Body<'tcx>, |
60c5eb7d XL |
925 | location: Location |
926 | ) { | |
f9f354fc XL |
927 | macro_rules! basic_blocks { |
928 | (mut) => (body.basic_blocks_mut()); | |
929 | () => (body.basic_blocks()); | |
fc512014 | 930 | } |
f9f354fc | 931 | let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block]; |
9e0c209e | 932 | if basic_block.statements.len() == location.statement_index { |
9fa01778 | 933 | if let Some(ref $($mutability)? terminator) = basic_block.terminator { |
48663c56 | 934 | self.visit_terminator(terminator, location) |
9e0c209e SL |
935 | } |
936 | } else { | |
9fa01778 | 937 | let statement = & $($mutability)? |
9e0c209e | 938 | basic_block.statements[location.statement_index]; |
48663c56 | 939 | self.visit_statement(statement, location) |
9e0c209e SL |
940 | } |
941 | } | |
92a42be0 SL |
942 | } |
943 | } | |
92a42be0 SL |
944 | } |
945 | ||
e74abb32 | 946 | macro_rules! visit_place_fns { |
ba9703b0 | 947 | (mut) => { |
e74abb32 XL |
948 | fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; |
949 | ||
950 | fn super_place( | |
951 | &mut self, | |
952 | place: &mut Place<'tcx>, | |
953 | context: PlaceContext, | |
954 | location: Location, | |
955 | ) { | |
f9f354fc | 956 | self.visit_local(&mut place.local, context, location); |
e74abb32 | 957 | |
ba9703b0 | 958 | if let Some(new_projection) = self.process_projection(&place.projection, location) { |
e74abb32 XL |
959 | place.projection = self.tcx().intern_place_elems(&new_projection); |
960 | } | |
961 | } | |
962 | ||
963 | fn process_projection( | |
964 | &mut self, | |
965 | projection: &'a [PlaceElem<'tcx>], | |
ba9703b0 | 966 | location: Location, |
e74abb32 XL |
967 | ) -> Option<Vec<PlaceElem<'tcx>>> { |
968 | let mut projection = Cow::Borrowed(projection); | |
969 | ||
970 | for i in 0..projection.len() { | |
f9f354fc | 971 | if let Some(&elem) = projection.get(i) { |
ba9703b0 | 972 | if let Some(elem) = self.process_projection_elem(elem, location) { |
e74abb32 XL |
973 | // This converts the borrowed projection into `Cow::Owned(_)` and returns a |
974 | // clone of the projection so we can mutate and reintern later. | |
975 | let vec = projection.to_mut(); | |
976 | vec[i] = elem; | |
977 | } | |
978 | } | |
979 | } | |
980 | ||
981 | match projection { | |
982 | Cow::Borrowed(_) => None, | |
983 | Cow::Owned(vec) => Some(vec), | |
984 | } | |
985 | } | |
986 | ||
987 | fn process_projection_elem( | |
988 | &mut self, | |
f9f354fc | 989 | elem: PlaceElem<'tcx>, |
ba9703b0 | 990 | location: Location, |
e74abb32 | 991 | ) -> Option<PlaceElem<'tcx>> { |
ba9703b0 XL |
992 | match elem { |
993 | PlaceElem::Index(local) => { | |
f9f354fc | 994 | let mut new_local = local; |
ba9703b0 XL |
995 | self.visit_local( |
996 | &mut new_local, | |
997 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), | |
998 | location, | |
999 | ); | |
1000 | ||
f9f354fc | 1001 | if new_local == local { None } else { Some(PlaceElem::Index(new_local)) } |
ba9703b0 XL |
1002 | } |
1003 | PlaceElem::Deref | |
1004 | | PlaceElem::Field(..) | |
1005 | | PlaceElem::ConstantIndex { .. } | |
1006 | | PlaceElem::Subslice { .. } | |
1007 | | PlaceElem::Downcast(..) => None, | |
1008 | } | |
e74abb32 | 1009 | } |
ba9703b0 | 1010 | }; |
e74abb32 | 1011 | |
ba9703b0 | 1012 | () => { |
e74abb32 XL |
1013 | fn visit_projection( |
1014 | &mut self, | |
6a06907d | 1015 | place_ref: PlaceRef<'tcx>, |
e74abb32 XL |
1016 | context: PlaceContext, |
1017 | location: Location, | |
1018 | ) { | |
6a06907d | 1019 | self.super_projection(place_ref, context, location); |
e74abb32 XL |
1020 | } |
1021 | ||
1022 | fn visit_projection_elem( | |
1023 | &mut self, | |
74b04a01 | 1024 | local: Local, |
e74abb32 | 1025 | proj_base: &[PlaceElem<'tcx>], |
f9f354fc | 1026 | elem: PlaceElem<'tcx>, |
e74abb32 XL |
1027 | context: PlaceContext, |
1028 | location: Location, | |
1029 | ) { | |
dfeec247 | 1030 | self.super_projection_elem(local, proj_base, elem, context, location); |
e74abb32 XL |
1031 | } |
1032 | ||
ba9703b0 | 1033 | fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { |
e74abb32 XL |
1034 | let mut context = context; |
1035 | ||
1036 | if !place.projection.is_empty() { | |
fc512014 XL |
1037 | if context.is_use() { |
1038 | // ^ Only change the context if it is a real use, not a "use" in debuginfo. | |
1039 | context = if context.is_mutating_use() { | |
1040 | PlaceContext::MutatingUse(MutatingUseContext::Projection) | |
1041 | } else { | |
1042 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) | |
1043 | }; | |
1044 | } | |
e74abb32 XL |
1045 | } |
1046 | ||
f9f354fc | 1047 | self.visit_local(&place.local, context, location); |
e74abb32 | 1048 | |
6a06907d | 1049 | self.visit_projection(place.as_ref(), context, location); |
e74abb32 XL |
1050 | } |
1051 | ||
1052 | fn super_projection( | |
1053 | &mut self, | |
6a06907d | 1054 | place_ref: PlaceRef<'tcx>, |
e74abb32 XL |
1055 | context: PlaceContext, |
1056 | location: Location, | |
1057 | ) { | |
6a06907d XL |
1058 | // FIXME: Use PlaceRef::iter_projections, once that exists. |
1059 | let mut cursor = place_ref.projection; | |
f9f354fc | 1060 | while let &[ref proj_base @ .., elem] = cursor { |
e74abb32 | 1061 | cursor = proj_base; |
6a06907d | 1062 | self.visit_projection_elem(place_ref.local, cursor, elem, context, location); |
e74abb32 XL |
1063 | } |
1064 | } | |
1065 | ||
1066 | fn super_projection_elem( | |
1067 | &mut self, | |
74b04a01 | 1068 | _local: Local, |
e74abb32 | 1069 | _proj_base: &[PlaceElem<'tcx>], |
f9f354fc | 1070 | elem: PlaceElem<'tcx>, |
e74abb32 XL |
1071 | _context: PlaceContext, |
1072 | location: Location, | |
1073 | ) { | |
1074 | match elem { | |
1075 | ProjectionElem::Field(_field, ty) => { | |
1076 | self.visit_ty(ty, TyContext::Location(location)); | |
1077 | } | |
1078 | ProjectionElem::Index(local) => { | |
1079 | self.visit_local( | |
f9f354fc | 1080 | &local, |
e74abb32 | 1081 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), |
ba9703b0 | 1082 | location, |
e74abb32 XL |
1083 | ); |
1084 | } | |
ba9703b0 XL |
1085 | ProjectionElem::Deref |
1086 | | ProjectionElem::Subslice { from: _, to: _, from_end: _ } | |
1087 | | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } | |
1088 | | ProjectionElem::Downcast(_, _) => {} | |
e74abb32 XL |
1089 | } |
1090 | } | |
ba9703b0 | 1091 | }; |
e74abb32 XL |
1092 | } |
1093 | ||
9cc50fc6 | 1094 | make_mir_visitor!(Visitor,); |
dfeec247 | 1095 | make_mir_visitor!(MutVisitor, mut); |
9cc50fc6 | 1096 | |
ff7c6d11 XL |
1097 | pub trait MirVisitable<'tcx> { |
1098 | fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>); | |
1099 | } | |
1100 | ||
1101 | impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> { | |
dfeec247 | 1102 | fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { |
48663c56 | 1103 | visitor.visit_statement(self, location) |
ff7c6d11 XL |
1104 | } |
1105 | } | |
1106 | ||
1107 | impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> { | |
dfeec247 | 1108 | fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { |
48663c56 | 1109 | visitor.visit_terminator(self, location) |
ff7c6d11 XL |
1110 | } |
1111 | } | |
1112 | ||
1113 | impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> { | |
dfeec247 | 1114 | fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { |
48663c56 | 1115 | visitor.visit_terminator(self.as_ref().unwrap(), location) |
ff7c6d11 XL |
1116 | } |
1117 | } | |
1118 | ||
abe05a73 XL |
1119 | /// Extra information passed to `visit_ty` and friends to give context |
1120 | /// about where the type etc appears. | |
e74abb32 | 1121 | #[derive(Debug)] |
abe05a73 XL |
1122 | pub enum TyContext { |
1123 | LocalDecl { | |
1124 | /// The index of the local variable we are visiting. | |
1125 | local: Local, | |
1126 | ||
1127 | /// The source location where this local variable was declared. | |
1128 | source_info: SourceInfo, | |
1129 | }, | |
1130 | ||
9fa01778 XL |
1131 | /// The inferred type of a user type annotation. |
1132 | UserTy(Span), | |
1133 | ||
abe05a73 XL |
1134 | /// The return type of the function. |
1135 | ReturnTy(SourceInfo), | |
1136 | ||
2c00a5a8 XL |
1137 | YieldTy(SourceInfo), |
1138 | ||
abe05a73 XL |
1139 | /// A type found at some location. |
1140 | Location(Location), | |
3b2f2976 XL |
1141 | } |
1142 | ||
c30ab7b3 | 1143 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
48663c56 | 1144 | pub enum NonMutatingUseContext { |
13cf67c4 XL |
1145 | /// Being inspected in some way, like loading a len. |
1146 | Inspect, | |
1147 | /// Consumed as part of an operand. | |
1148 | Copy, | |
1149 | /// Consumed as part of an operand. | |
1150 | Move, | |
1151 | /// Shared borrow. | |
48663c56 | 1152 | SharedBorrow, |
13cf67c4 | 1153 | /// Shallow borrow. |
48663c56 | 1154 | ShallowBorrow, |
13cf67c4 | 1155 | /// Unique borrow. |
48663c56 | 1156 | UniqueBorrow, |
dfeec247 XL |
1157 | /// AddressOf for *const pointer. |
1158 | AddressOf, | |
0731742a | 1159 | /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place. |
13cf67c4 XL |
1160 | /// For example, the projection `x.y` is not marked as a mutation in these cases: |
1161 | /// | |
1162 | /// z = x.y; | |
1163 | /// f(&x.y); | |
1164 | /// | |
1165 | Projection, | |
1166 | } | |
92a42be0 | 1167 | |
13cf67c4 | 1168 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
48663c56 | 1169 | pub enum MutatingUseContext { |
13cf67c4 XL |
1170 | /// Appears as LHS of an assignment. |
1171 | Store, | |
1172 | /// Can often be treated as a `Store`, but needs to be separate because | |
1173 | /// ASM is allowed to read outputs as well, so a `Store`-`AsmOutput` sequence | |
1174 | /// cannot be simplified the way a `Store`-`Store` can be. | |
ff7c6d11 | 1175 | AsmOutput, |
13cf67c4 | 1176 | /// Destination of a call. |
54a0048b | 1177 | Call, |
f9f354fc XL |
1178 | /// Destination of a yield. |
1179 | Yield, | |
13cf67c4 | 1180 | /// Being dropped. |
92a42be0 | 1181 | Drop, |
13cf67c4 | 1182 | /// Mutable borrow. |
48663c56 | 1183 | Borrow, |
dfeec247 XL |
1184 | /// AddressOf for *mut pointer. |
1185 | AddressOf, | |
0731742a | 1186 | /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place. |
13cf67c4 XL |
1187 | /// For example, the projection `x.y` is marked as a mutation in these cases: |
1188 | /// | |
1189 | /// x.y = ...; | |
1190 | /// f(&mut x.y); | |
1191 | /// | |
1192 | Projection, | |
a1dfa0c6 XL |
1193 | /// Retagging, a "Stacked Borrows" shadow state operation |
1194 | Retag, | |
13cf67c4 | 1195 | } |
92a42be0 | 1196 | |
13cf67c4 XL |
1197 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
1198 | pub enum NonUseContext { | |
1199 | /// Starting a storage live range. | |
5bcae85e | 1200 | StorageLive, |
13cf67c4 | 1201 | /// Ending a storage live range. |
5bcae85e | 1202 | StorageDead, |
13cf67c4 XL |
1203 | /// User type annotation assertions for NLL. |
1204 | AscribeUserTy, | |
60c5eb7d XL |
1205 | /// The data of an user variable, for debug info. |
1206 | VarDebugInfo, | |
92a42be0 | 1207 | } |
9e0c209e | 1208 | |
13cf67c4 | 1209 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
48663c56 XL |
1210 | pub enum PlaceContext { |
1211 | NonMutatingUse(NonMutatingUseContext), | |
1212 | MutatingUse(MutatingUseContext), | |
13cf67c4 XL |
1213 | NonUse(NonUseContext), |
1214 | } | |
1215 | ||
dc9dc135 | 1216 | impl PlaceContext { |
13cf67c4 | 1217 | /// Returns `true` if this place context represents a drop. |
6a06907d | 1218 | #[inline] |
9e0c209e | 1219 | pub fn is_drop(&self) -> bool { |
29967ef6 | 1220 | matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop)) |
13cf67c4 XL |
1221 | } |
1222 | ||
1223 | /// Returns `true` if this place context represents a borrow. | |
1224 | pub fn is_borrow(&self) -> bool { | |
29967ef6 XL |
1225 | matches!( |
1226 | self, | |
ba9703b0 XL |
1227 | PlaceContext::NonMutatingUse( |
1228 | NonMutatingUseContext::SharedBorrow | |
29967ef6 XL |
1229 | | NonMutatingUseContext::ShallowBorrow |
1230 | | NonMutatingUseContext::UniqueBorrow | |
1231 | ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) | |
1232 | ) | |
9e0c209e SL |
1233 | } |
1234 | ||
13cf67c4 | 1235 | /// Returns `true` if this place context represents a storage live or storage dead marker. |
6a06907d | 1236 | #[inline] |
9e0c209e | 1237 | pub fn is_storage_marker(&self) -> bool { |
29967ef6 XL |
1238 | matches!( |
1239 | self, | |
1240 | PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) | |
1241 | ) | |
9e0c209e SL |
1242 | } |
1243 | ||
13cf67c4 | 1244 | /// Returns `true` if this place context represents a use that potentially changes the value. |
6a06907d | 1245 | #[inline] |
9e0c209e | 1246 | pub fn is_mutating_use(&self) -> bool { |
29967ef6 | 1247 | matches!(self, PlaceContext::MutatingUse(..)) |
9e0c209e SL |
1248 | } |
1249 | ||
13cf67c4 | 1250 | /// Returns `true` if this place context represents a use that does not change the value. |
6a06907d | 1251 | #[inline] |
9e0c209e | 1252 | pub fn is_nonmutating_use(&self) -> bool { |
29967ef6 | 1253 | matches!(self, PlaceContext::NonMutatingUse(..)) |
9e0c209e SL |
1254 | } |
1255 | ||
13cf67c4 | 1256 | /// Returns `true` if this place context represents a use. |
6a06907d | 1257 | #[inline] |
9e0c209e | 1258 | pub fn is_use(&self) -> bool { |
29967ef6 | 1259 | !matches!(self, PlaceContext::NonUse(..)) |
13cf67c4 XL |
1260 | } |
1261 | ||
1262 | /// Returns `true` if this place context represents an assignment statement. | |
1263 | pub fn is_place_assignment(&self) -> bool { | |
29967ef6 XL |
1264 | matches!( |
1265 | self, | |
ba9703b0 XL |
1266 | PlaceContext::MutatingUse( |
1267 | MutatingUseContext::Store | |
29967ef6 XL |
1268 | | MutatingUseContext::Call |
1269 | | MutatingUseContext::AsmOutput, | |
1270 | ) | |
1271 | ) | |
9e0c209e SL |
1272 | } |
1273 | } |