]> git.proxmox.com Git - rustc.git/blob - src/librustc/mir/visit.rs
New upstream version 1.19.0+dfsg1
[rustc.git] / src / librustc / mir / visit.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use middle::const_val::ConstVal;
12 use hir::def_id::DefId;
13 use ty::subst::Substs;
14 use ty::{ClosureSubsts, Region, Ty};
15 use mir::*;
16 use rustc_const_math::ConstUsize;
17 use rustc_data_structures::indexed_vec::Idx;
18 use syntax_pos::Span;
19
20 // # The MIR Visitor
21 //
22 // ## Overview
23 //
24 // There are two visitors, one for immutable and one for mutable references,
25 // but both are generated by the following macro. The code is written according
26 // to the following conventions:
27 //
28 // - introduce a `visit_foo` and a `super_foo` method for every MIR type
29 // - `visit_foo`, by default, calls `super_foo`
30 // - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
31 //
32 // This allows you as a user to override `visit_foo` for types are
33 // interested in, and invoke (within that method) call
34 // `self.super_foo` to get the default behavior. Just as in an OO
35 // language, you should never call `super` methods ordinarily except
36 // in that circumstance.
37 //
38 // For the most part, we do not destructure things external to the
39 // MIR, e.g. types, spans, etc, but simply visit them and stop. This
40 // avoids duplication with other visitors like `TypeFoldable`.
41 //
42 // ## Updating
43 //
44 // The code is written in a very deliberate style intended to minimize
45 // the chance of things being overlooked. You'll notice that we always
46 // use pattern matching to reference fields and we ensure that all
47 // matches are exhaustive.
48 //
49 // For example, the `super_basic_block_data` method begins like this:
50 //
51 // ```rust
52 // fn super_basic_block_data(&mut self,
53 // block: BasicBlock,
54 // data: & $($mutability)* BasicBlockData<'tcx>) {
55 // let BasicBlockData {
56 // ref $($mutability)* statements,
57 // ref $($mutability)* terminator,
58 // is_cleanup: _
59 // } = *data;
60 //
61 // for statement in statements {
62 // self.visit_statement(block, statement);
63 // }
64 //
65 // ...
66 // }
67 // ```
68 //
69 // Here we used `let BasicBlockData { <fields> } = *data` deliberately,
70 // rather than writing `data.statements` in the body. This is because if one
71 // adds a new field to `BasicBlockData`, one will be forced to revise this code,
72 // and hence one will (hopefully) invoke the correct visit methods (if any).
73 //
74 // For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
75 // That means you never write `..` to skip over fields, nor do you write `_`
76 // to skip over variants in a `match`.
77 //
78 // The only place that `_` is acceptable is to match a field (or
79 // variant argument) that does not require visiting, as in
80 // `is_cleanup` above.
81
82 macro_rules! make_mir_visitor {
83 ($visitor_trait_name:ident, $($mutability:ident)*) => {
84 pub trait $visitor_trait_name<'tcx> {
85 // Override these, and call `self.super_xxx` to revert back to the
86 // default behavior.
87
88 fn visit_mir(&mut self, mir: & $($mutability)* Mir<'tcx>) {
89 self.super_mir(mir);
90 }
91
92 fn visit_basic_block_data(&mut self,
93 block: BasicBlock,
94 data: & $($mutability)* BasicBlockData<'tcx>) {
95 self.super_basic_block_data(block, data);
96 }
97
98 fn visit_visibility_scope_data(&mut self,
99 scope_data: & $($mutability)* VisibilityScopeData) {
100 self.super_visibility_scope_data(scope_data);
101 }
102
103 fn visit_statement(&mut self,
104 block: BasicBlock,
105 statement: & $($mutability)* Statement<'tcx>,
106 location: Location) {
107 self.super_statement(block, statement, location);
108 }
109
110 fn visit_assign(&mut self,
111 block: BasicBlock,
112 lvalue: & $($mutability)* Lvalue<'tcx>,
113 rvalue: & $($mutability)* Rvalue<'tcx>,
114 location: Location) {
115 self.super_assign(block, lvalue, rvalue, location);
116 }
117
118 fn visit_terminator(&mut self,
119 block: BasicBlock,
120 terminator: & $($mutability)* Terminator<'tcx>,
121 location: Location) {
122 self.super_terminator(block, terminator, location);
123 }
124
125 fn visit_terminator_kind(&mut self,
126 block: BasicBlock,
127 kind: & $($mutability)* TerminatorKind<'tcx>,
128 location: Location) {
129 self.super_terminator_kind(block, kind, location);
130 }
131
132 fn visit_assert_message(&mut self,
133 msg: & $($mutability)* AssertMessage<'tcx>,
134 location: Location) {
135 self.super_assert_message(msg, location);
136 }
137
138 fn visit_rvalue(&mut self,
139 rvalue: & $($mutability)* Rvalue<'tcx>,
140 location: Location) {
141 self.super_rvalue(rvalue, location);
142 }
143
144 fn visit_operand(&mut self,
145 operand: & $($mutability)* Operand<'tcx>,
146 location: Location) {
147 self.super_operand(operand, location);
148 }
149
150 fn visit_lvalue(&mut self,
151 lvalue: & $($mutability)* Lvalue<'tcx>,
152 context: LvalueContext<'tcx>,
153 location: Location) {
154 self.super_lvalue(lvalue, context, location);
155 }
156
157 fn visit_static(&mut self,
158 static_: & $($mutability)* Static<'tcx>,
159 context: LvalueContext<'tcx>,
160 location: Location) {
161 self.super_static(static_, context, location);
162 }
163
164 fn visit_projection(&mut self,
165 lvalue: & $($mutability)* LvalueProjection<'tcx>,
166 context: LvalueContext<'tcx>,
167 location: Location) {
168 self.super_projection(lvalue, context, location);
169 }
170
171 fn visit_projection_elem(&mut self,
172 lvalue: & $($mutability)* LvalueElem<'tcx>,
173 context: LvalueContext<'tcx>,
174 location: Location) {
175 self.super_projection_elem(lvalue, context, location);
176 }
177
178 fn visit_branch(&mut self,
179 source: BasicBlock,
180 target: BasicBlock) {
181 self.super_branch(source, target);
182 }
183
184 fn visit_constant(&mut self,
185 constant: & $($mutability)* Constant<'tcx>,
186 location: Location) {
187 self.super_constant(constant, location);
188 }
189
190 fn visit_literal(&mut self,
191 literal: & $($mutability)* Literal<'tcx>,
192 location: Location) {
193 self.super_literal(literal, location);
194 }
195
196 fn visit_def_id(&mut self,
197 def_id: & $($mutability)* DefId,
198 _: Location) {
199 self.super_def_id(def_id);
200 }
201
202 fn visit_span(&mut self,
203 span: & $($mutability)* Span) {
204 self.super_span(span);
205 }
206
207 fn visit_source_info(&mut self,
208 source_info: & $($mutability)* SourceInfo) {
209 self.super_source_info(source_info);
210 }
211
212 fn visit_ty(&mut self,
213 ty: & $($mutability)* Ty<'tcx>) {
214 self.super_ty(ty);
215 }
216
217 fn visit_substs(&mut self,
218 substs: & $($mutability)* &'tcx Substs<'tcx>) {
219 self.super_substs(substs);
220 }
221
222 fn visit_closure_substs(&mut self,
223 substs: & $($mutability)* ClosureSubsts<'tcx>) {
224 self.super_closure_substs(substs);
225 }
226
227 fn visit_const_val(&mut self,
228 const_val: & $($mutability)* ConstVal,
229 _: Location) {
230 self.super_const_val(const_val);
231 }
232
233 fn visit_const_int(&mut self,
234 const_int: &ConstInt,
235 _: Location) {
236 self.super_const_int(const_int);
237 }
238
239 fn visit_const_usize(&mut self,
240 const_usize: & $($mutability)* ConstUsize,
241 _: Location) {
242 self.super_const_usize(const_usize);
243 }
244
245 fn visit_local_decl(&mut self,
246 local_decl: & $($mutability)* LocalDecl<'tcx>) {
247 self.super_local_decl(local_decl);
248 }
249
250 fn visit_visibility_scope(&mut self,
251 scope: & $($mutability)* VisibilityScope) {
252 self.super_visibility_scope(scope);
253 }
254
255 // The `super_xxx` methods comprise the default behavior and are
256 // not meant to be overridden.
257
258 fn super_mir(&mut self,
259 mir: & $($mutability)* Mir<'tcx>) {
260 for index in 0..mir.basic_blocks().len() {
261 let block = BasicBlock::new(index);
262 self.visit_basic_block_data(block, &$($mutability)* mir[block]);
263 }
264
265 for scope in &$($mutability)* mir.visibility_scopes {
266 self.visit_visibility_scope_data(scope);
267 }
268
269 self.visit_ty(&$($mutability)* mir.return_ty);
270
271 for local_decl in &$($mutability)* mir.local_decls {
272 self.visit_local_decl(local_decl);
273 }
274
275 self.visit_span(&$($mutability)* mir.span);
276 }
277
278 fn super_basic_block_data(&mut self,
279 block: BasicBlock,
280 data: & $($mutability)* BasicBlockData<'tcx>) {
281 let BasicBlockData {
282 ref $($mutability)* statements,
283 ref $($mutability)* terminator,
284 is_cleanup: _
285 } = *data;
286
287 let mut index = 0;
288 for statement in statements {
289 let location = Location { block: block, statement_index: index };
290 self.visit_statement(block, statement, location);
291 index += 1;
292 }
293
294 if let Some(ref $($mutability)* terminator) = *terminator {
295 let location = Location { block: block, statement_index: index };
296 self.visit_terminator(block, terminator, location);
297 }
298 }
299
300 fn super_visibility_scope_data(&mut self,
301 scope_data: & $($mutability)* VisibilityScopeData) {
302 let VisibilityScopeData {
303 ref $($mutability)* span,
304 ref $($mutability)* parent_scope,
305 } = *scope_data;
306
307 self.visit_span(span);
308 if let Some(ref $($mutability)* parent_scope) = *parent_scope {
309 self.visit_visibility_scope(parent_scope);
310 }
311 }
312
313 fn super_statement(&mut self,
314 block: BasicBlock,
315 statement: & $($mutability)* Statement<'tcx>,
316 location: Location) {
317 let Statement {
318 ref $($mutability)* source_info,
319 ref $($mutability)* kind,
320 } = *statement;
321
322 self.visit_source_info(source_info);
323 match *kind {
324 StatementKind::Assign(ref $($mutability)* lvalue,
325 ref $($mutability)* rvalue) => {
326 self.visit_assign(block, lvalue, rvalue, location);
327 }
328 StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
329 self.visit_lvalue(lvalue, LvalueContext::Store, location);
330 }
331 StatementKind::StorageLive(ref $($mutability)* lvalue) => {
332 self.visit_lvalue(lvalue, LvalueContext::StorageLive, location);
333 }
334 StatementKind::StorageDead(ref $($mutability)* lvalue) => {
335 self.visit_lvalue(lvalue, LvalueContext::StorageDead, location);
336 }
337 StatementKind::InlineAsm { ref $($mutability)* outputs,
338 ref $($mutability)* inputs,
339 asm: _ } => {
340 for output in & $($mutability)* outputs[..] {
341 self.visit_lvalue(output, LvalueContext::Store, location);
342 }
343 for input in & $($mutability)* inputs[..] {
344 self.visit_operand(input, location);
345 }
346 }
347 StatementKind::Nop => {}
348 }
349 }
350
351 fn super_assign(&mut self,
352 _block: BasicBlock,
353 lvalue: &$($mutability)* Lvalue<'tcx>,
354 rvalue: &$($mutability)* Rvalue<'tcx>,
355 location: Location) {
356 self.visit_lvalue(lvalue, LvalueContext::Store, location);
357 self.visit_rvalue(rvalue, location);
358 }
359
360 fn super_terminator(&mut self,
361 block: BasicBlock,
362 terminator: &$($mutability)* Terminator<'tcx>,
363 location: Location) {
364 let Terminator {
365 ref $($mutability)* source_info,
366 ref $($mutability)* kind,
367 } = *terminator;
368
369 self.visit_source_info(source_info);
370 self.visit_terminator_kind(block, kind, location);
371 }
372
373 fn super_terminator_kind(&mut self,
374 block: BasicBlock,
375 kind: & $($mutability)* TerminatorKind<'tcx>,
376 source_location: Location) {
377 match *kind {
378 TerminatorKind::Goto { target } => {
379 self.visit_branch(block, target);
380 }
381
382 TerminatorKind::SwitchInt { ref $($mutability)* discr,
383 ref $($mutability)* switch_ty,
384 ref values,
385 ref targets } => {
386 self.visit_operand(discr, source_location);
387 self.visit_ty(switch_ty);
388 for value in &values[..] {
389 self.visit_const_int(value, source_location);
390 }
391 for &target in targets {
392 self.visit_branch(block, target);
393 }
394 }
395
396 TerminatorKind::Resume |
397 TerminatorKind::Return |
398 TerminatorKind::Unreachable => {
399 }
400
401 TerminatorKind::Drop { ref $($mutability)* location,
402 target,
403 unwind } => {
404 self.visit_lvalue(location, LvalueContext::Drop, source_location);
405 self.visit_branch(block, target);
406 unwind.map(|t| self.visit_branch(block, t));
407 }
408
409 TerminatorKind::DropAndReplace { ref $($mutability)* location,
410 ref $($mutability)* value,
411 target,
412 unwind } => {
413 self.visit_lvalue(location, LvalueContext::Drop, source_location);
414 self.visit_operand(value, source_location);
415 self.visit_branch(block, target);
416 unwind.map(|t| self.visit_branch(block, t));
417 }
418
419 TerminatorKind::Call { ref $($mutability)* func,
420 ref $($mutability)* args,
421 ref $($mutability)* destination,
422 cleanup } => {
423 self.visit_operand(func, source_location);
424 for arg in args {
425 self.visit_operand(arg, source_location);
426 }
427 if let Some((ref $($mutability)* destination, target)) = *destination {
428 self.visit_lvalue(destination, LvalueContext::Call, source_location);
429 self.visit_branch(block, target);
430 }
431 cleanup.map(|t| self.visit_branch(block, t));
432 }
433
434 TerminatorKind::Assert { ref $($mutability)* cond,
435 expected: _,
436 ref $($mutability)* msg,
437 target,
438 cleanup } => {
439 self.visit_operand(cond, source_location);
440 self.visit_assert_message(msg, source_location);
441 self.visit_branch(block, target);
442 cleanup.map(|t| self.visit_branch(block, t));
443 }
444 }
445 }
446
447 fn super_assert_message(&mut self,
448 msg: & $($mutability)* AssertMessage<'tcx>,
449 location: Location) {
450 match *msg {
451 AssertMessage::BoundsCheck {
452 ref $($mutability)* len,
453 ref $($mutability)* index
454 } => {
455 self.visit_operand(len, location);
456 self.visit_operand(index, location);
457 }
458 AssertMessage::Math(_) => {}
459 }
460 }
461
462 fn super_rvalue(&mut self,
463 rvalue: & $($mutability)* Rvalue<'tcx>,
464 location: Location) {
465 match *rvalue {
466 Rvalue::Use(ref $($mutability)* operand) => {
467 self.visit_operand(operand, location);
468 }
469
470 Rvalue::Repeat(ref $($mutability)* value,
471 ref $($mutability)* length) => {
472 self.visit_operand(value, location);
473 self.visit_const_usize(length, location);
474 }
475
476 Rvalue::Ref(r, bk, ref $($mutability)* path) => {
477 self.visit_lvalue(path, LvalueContext::Borrow {
478 region: r,
479 kind: bk
480 }, location);
481 }
482
483 Rvalue::Len(ref $($mutability)* path) => {
484 self.visit_lvalue(path, LvalueContext::Inspect, location);
485 }
486
487 Rvalue::Cast(_cast_kind,
488 ref $($mutability)* operand,
489 ref $($mutability)* ty) => {
490 self.visit_operand(operand, location);
491 self.visit_ty(ty);
492 }
493
494 Rvalue::BinaryOp(_bin_op,
495 ref $($mutability)* lhs,
496 ref $($mutability)* rhs) |
497 Rvalue::CheckedBinaryOp(_bin_op,
498 ref $($mutability)* lhs,
499 ref $($mutability)* rhs) => {
500 self.visit_operand(lhs, location);
501 self.visit_operand(rhs, location);
502 }
503
504 Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
505 self.visit_operand(op, location);
506 }
507
508 Rvalue::Discriminant(ref $($mutability)* lvalue) => {
509 self.visit_lvalue(lvalue, LvalueContext::Inspect, location);
510 }
511
512 Rvalue::NullaryOp(_op, ref $($mutability)* ty) => {
513 self.visit_ty(ty);
514 }
515
516 Rvalue::Aggregate(ref $($mutability)* kind,
517 ref $($mutability)* operands) => {
518 let kind = &$($mutability)* **kind;
519 match *kind {
520 AggregateKind::Array(ref $($mutability)* ty) => {
521 self.visit_ty(ty);
522 }
523 AggregateKind::Tuple => {
524 }
525 AggregateKind::Adt(_adt_def,
526 _variant_index,
527 ref $($mutability)* substs,
528 _active_field_index) => {
529 self.visit_substs(substs);
530 }
531 AggregateKind::Closure(ref $($mutability)* def_id,
532 ref $($mutability)* closure_substs) => {
533 self.visit_def_id(def_id, location);
534 self.visit_closure_substs(closure_substs);
535 }
536 }
537
538 for operand in operands {
539 self.visit_operand(operand, location);
540 }
541 }
542 }
543 }
544
545 fn super_operand(&mut self,
546 operand: & $($mutability)* Operand<'tcx>,
547 location: Location) {
548 match *operand {
549 Operand::Consume(ref $($mutability)* lvalue) => {
550 self.visit_lvalue(lvalue, LvalueContext::Consume, location);
551 }
552 Operand::Constant(ref $($mutability)* constant) => {
553 self.visit_constant(constant, location);
554 }
555 }
556 }
557
558 fn super_lvalue(&mut self,
559 lvalue: & $($mutability)* Lvalue<'tcx>,
560 context: LvalueContext<'tcx>,
561 location: Location) {
562 match *lvalue {
563 Lvalue::Local(_) => {
564 }
565 Lvalue::Static(ref $($mutability)* static_) => {
566 self.visit_static(static_, context, location);
567 }
568 Lvalue::Projection(ref $($mutability)* proj) => {
569 self.visit_projection(proj, context, location);
570 }
571 }
572 }
573
574 fn super_static(&mut self,
575 static_: & $($mutability)* Static<'tcx>,
576 _context: LvalueContext<'tcx>,
577 location: Location) {
578 let Static {
579 ref $($mutability)* def_id,
580 ref $($mutability)* ty,
581 } = *static_;
582 self.visit_def_id(def_id, location);
583 self.visit_ty(ty);
584 }
585
586 fn super_projection(&mut self,
587 proj: & $($mutability)* LvalueProjection<'tcx>,
588 context: LvalueContext<'tcx>,
589 location: Location) {
590 let Projection {
591 ref $($mutability)* base,
592 ref $($mutability)* elem,
593 } = *proj;
594 let context = if context.is_mutating_use() {
595 LvalueContext::Projection(Mutability::Mut)
596 } else {
597 LvalueContext::Projection(Mutability::Not)
598 };
599 self.visit_lvalue(base, context, location);
600 self.visit_projection_elem(elem, context, location);
601 }
602
603 fn super_projection_elem(&mut self,
604 proj: & $($mutability)* LvalueElem<'tcx>,
605 _context: LvalueContext<'tcx>,
606 location: Location) {
607 match *proj {
608 ProjectionElem::Deref => {
609 }
610 ProjectionElem::Subslice { from: _, to: _ } => {
611 }
612 ProjectionElem::Field(_field, ref $($mutability)* ty) => {
613 self.visit_ty(ty);
614 }
615 ProjectionElem::Index(ref $($mutability)* operand) => {
616 self.visit_operand(operand, location);
617 }
618 ProjectionElem::ConstantIndex { offset: _,
619 min_length: _,
620 from_end: _ } => {
621 }
622 ProjectionElem::Downcast(_adt_def, _variant_index) => {
623 }
624 }
625 }
626
627 fn super_local_decl(&mut self,
628 local_decl: & $($mutability)* LocalDecl<'tcx>) {
629 let LocalDecl {
630 mutability: _,
631 ref $($mutability)* ty,
632 name: _,
633 ref $($mutability)* source_info,
634 is_user_variable: _,
635 } = *local_decl;
636
637 self.visit_ty(ty);
638 self.visit_source_info(source_info);
639 }
640
641 fn super_visibility_scope(&mut self,
642 _scope: & $($mutability)* VisibilityScope) {
643 }
644
645 fn super_branch(&mut self,
646 _source: BasicBlock,
647 _target: BasicBlock) {
648 }
649
650 fn super_constant(&mut self,
651 constant: & $($mutability)* Constant<'tcx>,
652 location: Location) {
653 let Constant {
654 ref $($mutability)* span,
655 ref $($mutability)* ty,
656 ref $($mutability)* literal,
657 } = *constant;
658
659 self.visit_span(span);
660 self.visit_ty(ty);
661 self.visit_literal(literal, location);
662 }
663
664 fn super_literal(&mut self,
665 literal: & $($mutability)* Literal<'tcx>,
666 location: Location) {
667 match *literal {
668 Literal::Item { ref $($mutability)* def_id,
669 ref $($mutability)* substs } => {
670 self.visit_def_id(def_id, location);
671 self.visit_substs(substs);
672 }
673 Literal::Value { ref $($mutability)* value } => {
674 self.visit_const_val(value, location);
675 }
676 Literal::Promoted { index: _ } => {}
677 }
678 }
679
680 fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
681 }
682
683 fn super_span(&mut self, _span: & $($mutability)* Span) {
684 }
685
686 fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) {
687 let SourceInfo {
688 ref $($mutability)* span,
689 ref $($mutability)* scope,
690 } = *source_info;
691
692 self.visit_span(span);
693 self.visit_visibility_scope(scope);
694 }
695
696 fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
697 }
698
699 fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
700 }
701
702 fn super_closure_substs(&mut self,
703 _substs: & $($mutability)* ClosureSubsts<'tcx>) {
704 }
705
706 fn super_const_val(&mut self, _const_val: & $($mutability)* ConstVal) {
707 }
708
709 fn super_const_int(&mut self, _const_int: &ConstInt) {
710 }
711
712 fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) {
713 }
714
715 // Convenience methods
716
717 fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) {
718 let basic_block = & $($mutability)* mir[location.block];
719 if basic_block.statements.len() == location.statement_index {
720 if let Some(ref $($mutability)* terminator) = basic_block.terminator {
721 self.visit_terminator(location.block, terminator, location)
722 }
723 } else {
724 let statement = & $($mutability)*
725 basic_block.statements[location.statement_index];
726 self.visit_statement(location.block, statement, location)
727 }
728 }
729 }
730 }
731 }
732
733 make_mir_visitor!(Visitor,);
734 make_mir_visitor!(MutVisitor,mut);
735
736 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
737 pub enum LvalueContext<'tcx> {
738 // Appears as LHS of an assignment
739 Store,
740
741 // Dest of a call
742 Call,
743
744 // Being dropped
745 Drop,
746
747 // Being inspected in some way, like loading a len
748 Inspect,
749
750 // Being borrowed
751 Borrow { region: Region<'tcx>, kind: BorrowKind },
752
753 // Used as base for another lvalue, e.g. `x` in `x.y`.
754 //
755 // The `Mutability` argument specifies whether the projection is being performed in order to
756 // (potentially) mutate the lvalue. For example, the projection `x.y` is marked as a mutation
757 // in these cases:
758 //
759 // x.y = ...;
760 // f(&mut x.y);
761 //
762 // But not in these cases:
763 //
764 // z = x.y;
765 // f(&x.y);
766 Projection(Mutability),
767
768 // Consumed as part of an operand
769 Consume,
770
771 // Starting and ending a storage live range
772 StorageLive,
773 StorageDead,
774 }
775
776 impl<'tcx> LvalueContext<'tcx> {
777 /// Returns true if this lvalue context represents a drop.
778 pub fn is_drop(&self) -> bool {
779 match *self {
780 LvalueContext::Drop => true,
781 _ => false,
782 }
783 }
784
785 /// Returns true if this lvalue context represents a storage live or storage dead marker.
786 pub fn is_storage_marker(&self) -> bool {
787 match *self {
788 LvalueContext::StorageLive | LvalueContext::StorageDead => true,
789 _ => false,
790 }
791 }
792
793 /// Returns true if this lvalue context represents a storage live marker.
794 pub fn is_storage_live_marker(&self) -> bool {
795 match *self {
796 LvalueContext::StorageLive => true,
797 _ => false,
798 }
799 }
800
801 /// Returns true if this lvalue context represents a storage dead marker.
802 pub fn is_storage_dead_marker(&self) -> bool {
803 match *self {
804 LvalueContext::StorageDead => true,
805 _ => false,
806 }
807 }
808
809 /// Returns true if this lvalue context represents a use that potentially changes the value.
810 pub fn is_mutating_use(&self) -> bool {
811 match *self {
812 LvalueContext::Store | LvalueContext::Call |
813 LvalueContext::Borrow { kind: BorrowKind::Mut, .. } |
814 LvalueContext::Projection(Mutability::Mut) |
815 LvalueContext::Drop => true,
816 LvalueContext::Inspect |
817 LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
818 LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
819 LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
820 LvalueContext::StorageLive | LvalueContext::StorageDead => false,
821 }
822 }
823
824 /// Returns true if this lvalue context represents a use that does not change the value.
825 pub fn is_nonmutating_use(&self) -> bool {
826 match *self {
827 LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
828 LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
829 LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
830 LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
831 LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
832 LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead => false,
833 }
834 }
835
836 pub fn is_use(&self) -> bool {
837 self.is_mutating_use() || self.is_nonmutating_use()
838 }
839 }