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:
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`
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.
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`.
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.
30 //! For example, the `super_basic_block_data` method begins like this:
33 //! fn super_basic_block_data(&mut self,
34 //! block: BasicBlock,
35 //! data: & $($mutability)? BasicBlockData<'tcx>) {
36 //! let BasicBlockData {
42 //! for statement in statements {
43 //! self.visit_statement(block, statement);
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).
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`.
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.
64 use crate::ty
::subst
::SubstsRef
;
65 use crate::ty
::{CanonicalUserTypeAnnotation, Ty}
;
68 macro_rules
! make_mir_visitor
{
69 ($visitor_trait_name
:ident
, $
($mutability
:ident
)?
) => {
70 pub trait $visitor_trait_name
<'tcx
> {
71 // Override these, and call `self.super_xxx` to revert back to the
76 body
: &$
($mutability
)? Body
<'tcx
>,
78 self.super_body(body
);
81 fn visit_basic_block_data(&mut self,
83 data
: & $
($mutability
)? BasicBlockData
<'tcx
>) {
84 self.super_basic_block_data(block
, data
);
87 fn visit_source_scope_data(&mut self,
88 scope_data
: & $
($mutability
)? SourceScopeData
<'tcx
>) {
89 self.super_source_scope_data(scope_data
);
92 fn visit_statement(&mut self,
93 statement
: & $
($mutability
)? Statement
<'tcx
>,
95 self.super_statement(statement
, location
);
98 fn visit_assign(&mut self,
99 place
: & $
($mutability
)? Place
<'tcx
>,
100 rvalue
: & $
($mutability
)? Rvalue
<'tcx
>,
101 location
: Location
) {
102 self.super_assign(place
, rvalue
, location
);
105 fn visit_terminator(&mut self,
106 terminator
: & $
($mutability
)? Terminator
<'tcx
>,
107 location
: Location
) {
108 self.super_terminator(terminator
, location
);
111 fn visit_assert_message(&mut self,
112 msg
: & $
($mutability
)? AssertMessage
<'tcx
>,
113 location
: Location
) {
114 self.super_assert_message(msg
, location
);
117 fn visit_rvalue(&mut self,
118 rvalue
: & $
($mutability
)? Rvalue
<'tcx
>,
119 location
: Location
) {
120 self.super_rvalue(rvalue
, location
);
123 fn visit_operand(&mut self,
124 operand
: & $
($mutability
)? Operand
<'tcx
>,
125 location
: Location
) {
126 self.super_operand(operand
, location
);
129 fn visit_ascribe_user_ty(&mut self,
130 place
: & $
($mutability
)? Place
<'tcx
>,
131 variance
: & $
($mutability
)? ty
::Variance
,
132 user_ty
: & $
($mutability
)? UserTypeProjection
,
133 location
: Location
) {
134 self.super_ascribe_user_ty(place
, variance
, user_ty
, location
);
137 fn visit_coverage(&mut self,
138 coverage
: & $
($mutability
)? Coverage
,
139 location
: Location
) {
140 self.super_coverage(coverage
, location
);
143 fn visit_retag(&mut self,
144 kind
: & $
($mutability
)? RetagKind
,
145 place
: & $
($mutability
)? Place
<'tcx
>,
146 location
: Location
) {
147 self.super_retag(kind
, place
, location
);
150 fn visit_place(&mut self,
151 place
: & $
($mutability
)? Place
<'tcx
>,
152 context
: PlaceContext
,
153 location
: Location
) {
154 self.super_place(place
, context
, location
);
157 visit_place_fns
!($
($mutability
)?
);
159 fn visit_constant(&mut self,
160 constant
: & $
($mutability
)? Constant
<'tcx
>,
161 location
: Location
) {
162 self.super_constant(constant
, location
);
165 // The macro results in a false positive of sorts, where &mut Span
166 // is fine, but &Span is not; just allow the lint.
167 #[allow(rustc::pass_by_value)]
168 fn visit_span(&mut self,
169 span
: & $
($mutability
)? Span
) {
170 self.super_span(span
);
173 fn visit_source_info(&mut self,
174 source_info
: & $
($mutability
)? SourceInfo
) {
175 self.super_source_info(source_info
);
178 fn visit_ty(&mut self,
179 ty
: $
(& $mutability
)? Ty
<'tcx
>,
184 fn visit_user_type_projection(
186 ty
: & $
($mutability
)? UserTypeProjection
,
188 self.super_user_type_projection(ty
);
191 fn visit_user_type_annotation(
193 index
: UserTypeAnnotationIndex
,
194 ty
: & $
($mutability
)? CanonicalUserTypeAnnotation
<'tcx
>,
196 self.super_user_type_annotation(index
, ty
);
199 fn visit_region(&mut self,
200 region
: $
(& $mutability
)? ty
::Region
<'tcx
>,
202 self.super_region(region
);
205 fn visit_const(&mut self,
206 constant
: $
(& $mutability
)? ty
::Const
<'tcx
>,
208 self.super_const(constant
);
211 fn visit_substs(&mut self,
212 substs
: & $
($mutability
)? SubstsRef
<'tcx
>,
214 self.super_substs(substs
);
217 fn visit_local_decl(&mut self,
219 local_decl
: & $
($mutability
)? LocalDecl
<'tcx
>) {
220 self.super_local_decl(local
, local_decl
);
223 fn visit_var_debug_info(&mut self,
224 var_debug_info
: & $
($mutability
)* VarDebugInfo
<'tcx
>) {
225 self.super_var_debug_info(var_debug_info
);
228 #[allow(rustc::pass_by_value)]
229 fn visit_local(&mut self,
230 _local
: & $
($mutability
)? Local
,
231 _context
: PlaceContext
,
232 _location
: Location
) {
235 #[allow(rustc::pass_by_value)]
236 fn visit_source_scope(&mut self,
237 scope
: & $
($mutability
)? SourceScope
) {
238 self.super_source_scope(scope
);
241 // The `super_xxx` methods comprise the default behavior and are
242 // not meant to be overridden.
246 body
: &$
($mutability
)? Body
<'tcx
>,
248 let span
= body
.span
;
249 if let Some(gen
) = &$
($mutability
)? body
.generator
{
250 if let Some(yield_ty
) = $
(& $mutability
)? gen
.yield_ty
{
253 TyContext
::YieldTy(SourceInfo
::outermost(span
))
258 // for best performance, we want to use an iterator rather
259 // than a for-loop, to avoid calling `body::Body::invalidate` for
261 macro_rules
! basic_blocks
{
262 (mut) => (body
.basic_blocks_mut().iter_enumerated_mut());
263 () => (body
.basic_blocks().iter_enumerated());
265 for (bb
, data
) in basic_blocks
!($
($mutability
)?
) {
266 self.visit_basic_block_data(bb
, data
);
269 for scope
in &$
($mutability
)? body
.source_scopes
{
270 self.visit_source_scope_data(scope
);
274 $
(& $mutability
)? body
.return_ty(),
275 TyContext
::ReturnTy(SourceInfo
::outermost(body
.span
))
278 for local
in body
.local_decls
.indices() {
279 self.visit_local_decl(local
, & $
($mutability
)? body
.local_decls
[local
]);
282 macro_rules
! type_annotations
{
283 (mut) => (body
.user_type_annotations
.iter_enumerated_mut());
284 () => (body
.user_type_annotations
.iter_enumerated());
287 for (index
, annotation
) in type_annotations
!($
($mutability
)?
) {
288 self.visit_user_type_annotation(
293 for var_debug_info
in &$
($mutability
)? body
.var_debug_info
{
294 self.visit_var_debug_info(var_debug_info
);
297 self.visit_span(&$
($mutability
)? body
.span
);
299 for const_
in &$
($mutability
)? body
.required_consts
{
300 let location
= START_BLOCK
.start_location();
301 self.visit_constant(const_
, location
);
305 fn super_basic_block_data(&mut self,
307 data
: & $
($mutability
)? BasicBlockData
<'tcx
>) {
315 for statement
in statements
{
316 let location
= Location { block, statement_index: index }
;
317 self.visit_statement(statement
, location
);
321 if let Some(terminator
) = terminator
{
322 let location
= Location { block, statement_index: index }
;
323 self.visit_terminator(terminator
, location
);
327 fn super_source_scope_data(
329 scope_data
: & $
($mutability
)? SourceScopeData
<'tcx
>,
331 let SourceScopeData
{
335 inlined_parent_scope
,
339 self.visit_span(span
);
340 if let Some(parent_scope
) = parent_scope
{
341 self.visit_source_scope(parent_scope
);
343 if let Some((callee
, callsite_span
)) = inlined
{
344 let location
= START_BLOCK
.start_location();
346 self.visit_span(callsite_span
);
348 let ty
::Instance { def: callee_def, substs: callee_substs }
= callee
;
350 ty
::InstanceDef
::Item(_def_id
) => {}
352 ty
::InstanceDef
::Intrinsic(_def_id
) |
353 ty
::InstanceDef
::VtableShim(_def_id
) |
354 ty
::InstanceDef
::ReifyShim(_def_id
) |
355 ty
::InstanceDef
::Virtual(_def_id
, _
) |
356 ty
::InstanceDef
::ClosureOnceShim { call_once: _def_id, track_caller: _ }
|
357 ty
::InstanceDef
::DropGlue(_def_id
, None
) => {}
359 ty
::InstanceDef
::FnPtrShim(_def_id
, ty
) |
360 ty
::InstanceDef
::DropGlue(_def_id
, Some(ty
)) |
361 ty
::InstanceDef
::CloneShim(_def_id
, ty
) => {
362 // FIXME(eddyb) use a better `TyContext` here.
363 self.visit_ty($
(& $mutability
)?
*ty
, TyContext
::Location(location
));
366 self.visit_substs(callee_substs
, location
);
368 if let Some(inlined_parent_scope
) = inlined_parent_scope
{
369 self.visit_source_scope(inlined_parent_scope
);
373 fn super_statement(&mut self,
374 statement
: & $
($mutability
)? Statement
<'tcx
>,
375 location
: Location
) {
381 self.visit_source_info(source_info
);
383 StatementKind
::Assign(
384 box(ref $
($mutability
)? place
, ref $
($mutability
)? rvalue
)
386 self.visit_assign(place
, rvalue
, location
);
388 StatementKind
::FakeRead(box (_
, place
)) => {
391 PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Inspect
),
395 StatementKind
::SetDiscriminant { place, .. }
=> {
398 PlaceContext
::MutatingUse(MutatingUseContext
::Store
),
402 StatementKind
::StorageLive(local
) => {
405 PlaceContext
::NonUse(NonUseContext
::StorageLive
),
409 StatementKind
::StorageDead(local
) => {
412 PlaceContext
::NonUse(NonUseContext
::StorageDead
),
416 StatementKind
::Retag(kind
, place
) => {
417 self.visit_retag(kind
, place
, location
);
419 StatementKind
::AscribeUserType(
420 box(ref $
($mutability
)? place
, ref $
($mutability
)? user_ty
),
423 self.visit_ascribe_user_ty(place
, variance
, user_ty
, location
);
425 StatementKind
::Coverage(coverage
) => {
431 StatementKind
::CopyNonOverlapping(box crate::mir
::CopyNonOverlapping
{
432 ref $
($mutability
)? src
,
433 ref $
($mutability
)? dst
,
434 ref $
($mutability
)? count
,
436 self.visit_operand(src
, location
);
437 self.visit_operand(dst
, location
);
438 self.visit_operand(count
, location
)
440 StatementKind
::Nop
=> {}
444 fn super_assign(&mut self,
445 place
: &$
($mutability
)? Place
<'tcx
>,
446 rvalue
: &$
($mutability
)? Rvalue
<'tcx
>,
447 location
: Location
) {
450 PlaceContext
::MutatingUse(MutatingUseContext
::Store
),
453 self.visit_rvalue(rvalue
, location
);
456 fn super_terminator(&mut self,
457 terminator
: &$
($mutability
)? Terminator
<'tcx
>,
458 location
: Location
) {
459 let Terminator { source_info, kind }
= terminator
;
461 self.visit_source_info(source_info
);
463 TerminatorKind
::Goto { .. }
|
464 TerminatorKind
::Resume
|
465 TerminatorKind
::Abort
|
466 TerminatorKind
::GeneratorDrop
|
467 TerminatorKind
::Unreachable
|
468 TerminatorKind
::FalseEdge { .. }
|
469 TerminatorKind
::FalseUnwind { .. }
=> {
472 TerminatorKind
::Return
=> {
473 // `return` logically moves from the return place `_0`. Note that the place
474 // cannot be changed by any visitor, though.
475 let $
($mutability
)? local
= RETURN_PLACE
;
477 & $
($mutability
)? local
,
478 PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Move
),
485 "`MutVisitor` tried to mutate return place of `return` terminator"
489 TerminatorKind
::SwitchInt
{
494 self.visit_operand(discr
, location
);
495 self.visit_ty($
(& $mutability
)?
*switch_ty
, TyContext
::Location(location
));
498 TerminatorKind
::Drop
{
505 PlaceContext
::MutatingUse(MutatingUseContext
::Drop
),
510 TerminatorKind
::DropAndReplace
{
518 PlaceContext
::MutatingUse(MutatingUseContext
::Drop
),
521 self.visit_operand(value
, location
);
524 TerminatorKind
::Call
{
532 self.visit_operand(func
, location
);
534 self.visit_operand(arg
, location
);
536 if let Some((destination
, _
)) = destination
{
539 PlaceContext
::MutatingUse(MutatingUseContext
::Call
),
545 TerminatorKind
::Assert
{
552 self.visit_operand(cond
, location
);
553 self.visit_assert_message(msg
, location
);
556 TerminatorKind
::Yield
{
562 self.visit_operand(value
, location
);
565 PlaceContext
::MutatingUse(MutatingUseContext
::Yield
),
570 TerminatorKind
::InlineAsm
{
580 InlineAsmOperand
::In { value, .. }
=> {
581 self.visit_operand(value
, location
);
583 InlineAsmOperand
::Out { place: Some(place), .. }
=> {
586 PlaceContext
::MutatingUse(MutatingUseContext
::AsmOutput
),
590 InlineAsmOperand
::InOut { in_value, out_place, .. }
=> {
591 self.visit_operand(in_value
, location
);
592 if let Some(out_place
) = out_place
{
595 PlaceContext
::MutatingUse(MutatingUseContext
::AsmOutput
),
600 InlineAsmOperand
::Const { value }
601 | InlineAsmOperand
::SymFn { value }
=> {
602 self.visit_constant(value
, location
);
604 InlineAsmOperand
::Out { place: None, .. }
605 | InlineAsmOperand
::SymStatic { def_id: _ }
=> {}
612 fn super_assert_message(&mut self,
613 msg
: & $
($mutability
)? AssertMessage
<'tcx
>,
614 location
: Location
) {
615 use crate::mir
::AssertKind
::*;
617 BoundsCheck { len, index }
=> {
618 self.visit_operand(len
, location
);
619 self.visit_operand(index
, location
);
621 Overflow(_
, l
, r
) => {
622 self.visit_operand(l
, location
);
623 self.visit_operand(r
, location
);
625 OverflowNeg(op
) | DivisionByZero(op
) | RemainderByZero(op
) => {
626 self.visit_operand(op
, location
);
628 ResumedAfterReturn(_
) | ResumedAfterPanic(_
) => {
634 fn super_rvalue(&mut self,
635 rvalue
: & $
($mutability
)? Rvalue
<'tcx
>,
636 location
: Location
) {
638 Rvalue
::Use(operand
) => {
639 self.visit_operand(operand
, location
);
642 Rvalue
::Repeat(value
, _
) => {
643 self.visit_operand(value
, location
);
646 Rvalue
::ThreadLocalRef(_
) => {}
648 Rvalue
::Ref(r
, bk
, path
) => {
649 self.visit_region($
(& $mutability
)?
*r
, location
);
651 BorrowKind
::Shared
=> PlaceContext
::NonMutatingUse(
652 NonMutatingUseContext
::SharedBorrow
654 BorrowKind
::Shallow
=> PlaceContext
::NonMutatingUse(
655 NonMutatingUseContext
::ShallowBorrow
657 BorrowKind
::Unique
=> PlaceContext
::NonMutatingUse(
658 NonMutatingUseContext
::UniqueBorrow
660 BorrowKind
::Mut { .. }
=>
661 PlaceContext
::MutatingUse(MutatingUseContext
::Borrow
),
663 self.visit_place(path
, ctx
, location
);
666 Rvalue
::AddressOf(m
, path
) => {
668 Mutability
::Mut
=> PlaceContext
::MutatingUse(
669 MutatingUseContext
::AddressOf
671 Mutability
::Not
=> PlaceContext
::NonMutatingUse(
672 NonMutatingUseContext
::AddressOf
675 self.visit_place(path
, ctx
, location
);
678 Rvalue
::Len(path
) => {
681 PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Inspect
),
686 Rvalue
::Cast(_cast_kind
, operand
, ty
) => {
687 self.visit_operand(operand
, location
);
688 self.visit_ty($
(& $mutability
)?
*ty
, TyContext
::Location(location
));
691 Rvalue
::BinaryOp(_bin_op
, box(lhs
, rhs
))
692 | Rvalue
::CheckedBinaryOp(_bin_op
, box(lhs
, rhs
)) => {
693 self.visit_operand(lhs
, location
);
694 self.visit_operand(rhs
, location
);
697 Rvalue
::UnaryOp(_un_op
, op
) => {
698 self.visit_operand(op
, location
);
701 Rvalue
::Discriminant(place
) => {
704 PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Inspect
),
709 Rvalue
::NullaryOp(_op
, ty
) => {
710 self.visit_ty($
(& $mutability
)?
*ty
, TyContext
::Location(location
));
713 Rvalue
::Aggregate(kind
, operands
) => {
714 let kind
= &$
($mutability
)?
**kind
;
716 AggregateKind
::Array(ty
) => {
717 self.visit_ty($
(& $mutability
)?
*ty
, TyContext
::Location(location
));
719 AggregateKind
::Tuple
=> {
728 self.visit_substs(substs
, location
);
730 AggregateKind
::Closure(
734 self.visit_substs(closure_substs
, location
);
736 AggregateKind
::Generator(
741 self.visit_substs(generator_substs
, location
);
745 for operand
in operands
{
746 self.visit_operand(operand
, location
);
750 Rvalue
::ShallowInitBox(operand
, ty
) => {
751 self.visit_operand(operand
, location
);
752 self.visit_ty($
(& $mutability
)?
*ty
, TyContext
::Location(location
));
757 fn super_operand(&mut self,
758 operand
: & $
($mutability
)? Operand
<'tcx
>,
759 location
: Location
) {
761 Operand
::Copy(place
) => {
764 PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Copy
),
768 Operand
::Move(place
) => {
771 PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Move
),
775 Operand
::Constant(constant
) => {
776 self.visit_constant(constant
, location
);
781 fn super_ascribe_user_ty(&mut self,
782 place
: & $
($mutability
)? Place
<'tcx
>,
783 _variance
: & $
($mutability
)? ty
::Variance
,
784 user_ty
: & $
($mutability
)? UserTypeProjection
,
785 location
: Location
) {
788 PlaceContext
::NonUse(NonUseContext
::AscribeUserTy
),
791 self.visit_user_type_projection(user_ty
);
794 fn super_coverage(&mut self,
795 _coverage
: & $
($mutability
)? Coverage
,
796 _location
: Location
) {
799 fn super_retag(&mut self,
800 _kind
: & $
($mutability
)? RetagKind
,
801 place
: & $
($mutability
)? Place
<'tcx
>,
802 location
: Location
) {
805 PlaceContext
::MutatingUse(MutatingUseContext
::Retag
),
810 fn super_local_decl(&mut self,
812 local_decl
: & $
($mutability
)? LocalDecl
<'tcx
>) {
823 self.visit_ty($
(& $mutability
)?
*ty
, TyContext
::LocalDecl
{
825 source_info
: *source_info
,
827 if let Some(user_ty
) = user_ty
{
828 for (user_ty
, _
) in & $
($mutability
)? user_ty
.contents
{
829 self.visit_user_type_projection(user_ty
);
832 self.visit_source_info(source_info
);
835 fn super_var_debug_info(&mut self,
836 var_debug_info
: & $
($mutability
)? VarDebugInfo
<'tcx
>) {
843 self.visit_source_info(source_info
);
844 let location
= START_BLOCK
.start_location();
846 VarDebugInfoContents
::Const(c
) => self.visit_constant(c
, location
),
847 VarDebugInfoContents
::Place(place
) =>
850 PlaceContext
::NonUse(NonUseContext
::VarDebugInfo
),
856 #[allow(rustc::pass_by_value)]
857 fn super_source_scope(&mut self,
858 _scope
: & $
($mutability
)? SourceScope
) {
861 fn super_constant(&mut self,
862 constant
: & $
($mutability
)? Constant
<'tcx
>,
863 location
: Location
) {
870 self.visit_span(span
);
871 drop(user_ty
); // no visit method for this
873 ConstantKind
::Ty(ct
) => self.visit_const($
(& $mutability
)?
*ct
, location
),
874 ConstantKind
::Val(_
, ty
) => self.visit_ty($
(& $mutability
)?
*ty
, TyContext
::Location(location
)),
878 // The macro results in a false positive of sorts, where &mut Span
879 // is fine, but &Span is not; just allow the lint.
880 #[allow(rustc::pass_by_value)]
881 fn super_span(&mut self, _span
: & $
($mutability
)? Span
) {
884 fn super_source_info(&mut self, source_info
: & $
($mutability
)? SourceInfo
) {
890 self.visit_span(span
);
891 self.visit_source_scope(scope
);
894 fn super_user_type_projection(
896 _ty
: & $
($mutability
)? UserTypeProjection
,
900 fn super_user_type_annotation(
902 _index
: UserTypeAnnotationIndex
,
903 ty
: & $
($mutability
)? CanonicalUserTypeAnnotation
<'tcx
>,
905 self.visit_span(& $
($mutability
)? ty
.span
);
906 self.visit_ty($
(& $mutability
)? ty
.inferred_ty
, TyContext
::UserTy(ty
.span
));
909 fn super_ty(&mut self, _ty
: $
(& $mutability
)? Ty
<'tcx
>) {
912 fn super_region(&mut self, _region
: $
(& $mutability
)? ty
::Region
<'tcx
>) {
915 fn super_const(&mut self, _const
: $
(& $mutability
)? ty
::Const
<'tcx
>) {
918 fn super_substs(&mut self, _substs
: & $
($mutability
)? SubstsRef
<'tcx
>) {
921 // Convenience methods
925 body
: &$
($mutability
)? Body
<'tcx
>,
928 macro_rules
! basic_blocks
{
929 (mut) => (body
.basic_blocks_mut());
930 () => (body
.basic_blocks());
932 let basic_block
= & $
($mutability
)? basic_blocks
!($
($mutability
)?
)[location
.block
];
933 if basic_block
.statements
.len() == location
.statement_index
{
934 if let Some(ref $
($mutability
)? terminator
) = basic_block
.terminator
{
935 self.visit_terminator(terminator
, location
)
938 let statement
= & $
($mutability
)?
939 basic_block
.statements
[location
.statement_index
];
940 self.visit_statement(statement
, location
)
947 macro_rules
! visit_place_fns
{
949 fn tcx
<'a
>(&'a
self) -> TyCtxt
<'tcx
>;
953 place
: &mut Place
<'tcx
>,
954 context
: PlaceContext
,
957 self.visit_local(&mut place
.local
, context
, location
);
959 if let Some(new_projection
) = self.process_projection(&place
.projection
, location
) {
960 place
.projection
= self.tcx().intern_place_elems(&new_projection
);
964 fn process_projection
<'a
>(
966 projection
: &'a
[PlaceElem
<'tcx
>],
968 ) -> Option
<Vec
<PlaceElem
<'tcx
>>> {
969 let mut projection
= Cow
::Borrowed(projection
);
971 for i
in 0..projection
.len() {
972 if let Some(&elem
) = projection
.get(i
) {
973 if let Some(elem
) = self.process_projection_elem(elem
, location
) {
974 // This converts the borrowed projection into `Cow::Owned(_)` and returns a
975 // clone of the projection so we can mutate and reintern later.
976 let vec
= projection
.to_mut();
983 Cow
::Borrowed(_
) => None
,
984 Cow
::Owned(vec
) => Some(vec
),
988 fn process_projection_elem(
990 elem
: PlaceElem
<'tcx
>,
992 ) -> Option
<PlaceElem
<'tcx
>> {
994 PlaceElem
::Index(local
) => {
995 let mut new_local
= local
;
998 PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Copy
),
1002 if new_local
== local { None }
else { Some(PlaceElem::Index(new_local)) }
1004 PlaceElem
::Field(field
, ty
) => {
1005 let mut new_ty
= ty
;
1006 self.visit_ty(&mut new_ty
, TyContext
::Location(location
));
1007 if ty
!= new_ty { Some(PlaceElem::Field(field, new_ty)) }
else { None }
1010 | PlaceElem
::ConstantIndex { .. }
1011 | PlaceElem
::Subslice { .. }
1012 | PlaceElem
::Downcast(..) => None
,
1018 fn visit_projection(
1020 place_ref
: PlaceRef
<'tcx
>,
1021 context
: PlaceContext
,
1024 self.super_projection(place_ref
, context
, location
);
1027 fn visit_projection_elem(
1030 proj_base
: &[PlaceElem
<'tcx
>],
1031 elem
: PlaceElem
<'tcx
>,
1032 context
: PlaceContext
,
1035 self.super_projection_elem(local
, proj_base
, elem
, context
, location
);
1038 fn super_place(&mut self, place
: &Place
<'tcx
>, context
: PlaceContext
, location
: Location
) {
1039 let mut context
= context
;
1041 if !place
.projection
.is_empty() {
1042 if context
.is_use() {
1043 // ^ Only change the context if it is a real use, not a "use" in debuginfo.
1044 context
= if context
.is_mutating_use() {
1045 PlaceContext
::MutatingUse(MutatingUseContext
::Projection
)
1047 PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Projection
)
1052 self.visit_local(&place
.local
, context
, location
);
1054 self.visit_projection(place
.as_ref(), context
, location
);
1057 fn super_projection(
1059 place_ref
: PlaceRef
<'tcx
>,
1060 context
: PlaceContext
,
1063 // FIXME: Use PlaceRef::iter_projections, once that exists.
1064 let mut cursor
= place_ref
.projection
;
1065 while let &[ref proj_base @
.., elem
] = cursor
{
1067 self.visit_projection_elem(place_ref
.local
, cursor
, elem
, context
, location
);
1071 fn super_projection_elem(
1074 _proj_base
: &[PlaceElem
<'tcx
>],
1075 elem
: PlaceElem
<'tcx
>,
1076 _context
: PlaceContext
,
1080 ProjectionElem
::Field(_field
, ty
) => {
1081 self.visit_ty(ty
, TyContext
::Location(location
));
1083 ProjectionElem
::Index(local
) => {
1086 PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Copy
),
1090 ProjectionElem
::Deref
1091 | ProjectionElem
::Subslice { from: _, to: _, from_end: _ }
1092 | ProjectionElem
::ConstantIndex { offset: _, min_length: _, from_end: _ }
1093 | ProjectionElem
::Downcast(_
, _
) => {}
1099 make_mir_visitor
!(Visitor
,);
1100 make_mir_visitor
!(MutVisitor
, mut);
1102 pub trait MirVisitable
<'tcx
> {
1103 fn apply(&self, location
: Location
, visitor
: &mut dyn Visitor
<'tcx
>);
1106 impl<'tcx
> MirVisitable
<'tcx
> for Statement
<'tcx
> {
1107 fn apply(&self, location
: Location
, visitor
: &mut dyn Visitor
<'tcx
>) {
1108 visitor
.visit_statement(self, location
)
1112 impl<'tcx
> MirVisitable
<'tcx
> for Terminator
<'tcx
> {
1113 fn apply(&self, location
: Location
, visitor
: &mut dyn Visitor
<'tcx
>) {
1114 visitor
.visit_terminator(self, location
)
1118 impl<'tcx
> MirVisitable
<'tcx
> for Option
<Terminator
<'tcx
>> {
1119 fn apply(&self, location
: Location
, visitor
: &mut dyn Visitor
<'tcx
>) {
1120 visitor
.visit_terminator(self.as_ref().unwrap(), location
)
1124 /// Extra information passed to `visit_ty` and friends to give context
1125 /// about where the type etc appears.
1127 pub enum TyContext
{
1129 /// The index of the local variable we are visiting.
1132 /// The source location where this local variable was declared.
1133 source_info
: SourceInfo
,
1136 /// The inferred type of a user type annotation.
1139 /// The return type of the function.
1140 ReturnTy(SourceInfo
),
1142 YieldTy(SourceInfo
),
1144 /// A type found at some location.
1148 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1149 pub enum NonMutatingUseContext
{
1150 /// Being inspected in some way, like loading a len.
1152 /// Consumed as part of an operand.
1154 /// Consumed as part of an operand.
1162 /// AddressOf for *const pointer.
1164 /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
1165 /// For example, the projection `x.y` is not marked as a mutation in these cases:
1173 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1174 pub enum MutatingUseContext
{
1175 /// Appears as LHS of an assignment.
1177 /// Output operand of an inline assembly block.
1179 /// Destination of a call.
1181 /// Destination of a yield.
1187 /// AddressOf for *mut pointer.
1189 /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
1190 /// For example, the projection `x.y` is marked as a mutation in these cases:
1196 /// Retagging, a "Stacked Borrows" shadow state operation
1200 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1201 pub enum NonUseContext
{
1202 /// Starting a storage live range.
1204 /// Ending a storage live range.
1206 /// User type annotation assertions for NLL.
1208 /// The data of a user variable, for debug info.
1212 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1213 pub enum PlaceContext
{
1214 NonMutatingUse(NonMutatingUseContext
),
1215 MutatingUse(MutatingUseContext
),
1216 NonUse(NonUseContext
),
1220 /// Returns `true` if this place context represents a drop.
1222 pub fn is_drop(&self) -> bool
{
1223 matches
!(self, PlaceContext
::MutatingUse(MutatingUseContext
::Drop
))
1226 /// Returns `true` if this place context represents a borrow.
1227 pub fn is_borrow(&self) -> bool
{
1230 PlaceContext
::NonMutatingUse(
1231 NonMutatingUseContext
::SharedBorrow
1232 | NonMutatingUseContext
::ShallowBorrow
1233 | NonMutatingUseContext
::UniqueBorrow
1234 ) | PlaceContext
::MutatingUse(MutatingUseContext
::Borrow
)
1238 /// Returns `true` if this place context represents a storage live or storage dead marker.
1240 pub fn is_storage_marker(&self) -> bool
{
1243 PlaceContext
::NonUse(NonUseContext
::StorageLive
| NonUseContext
::StorageDead
)
1247 /// Returns `true` if this place context represents a use that potentially changes the value.
1249 pub fn is_mutating_use(&self) -> bool
{
1250 matches
!(self, PlaceContext
::MutatingUse(..))
1253 /// Returns `true` if this place context represents a use.
1255 pub fn is_use(&self) -> bool
{
1256 !matches
!(self, PlaceContext
::NonUse(..))
1259 /// Returns `true` if this place context represents an assignment statement.
1260 pub fn is_place_assignment(&self) -> bool
{
1263 PlaceContext
::MutatingUse(
1264 MutatingUseContext
::Store
1265 | MutatingUseContext
::Call
1266 | MutatingUseContext
::AsmOutput
,