rustc_middle/mir/
visit.rs

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 `make_mir_visitor` macro.
7//! The code is written according 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 to override `visit_foo` for types you 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//! ```ignore (pseudo-rust)
33//! fn super_basic_block_data(
34//!     &mut self,
35//!     block: BasicBlock,
36//!     data: & $($mutability)? BasicBlockData<'tcx>
37//! ) {
38//!     let BasicBlockData {
39//!         statements,
40//!         terminator,
41//!         is_cleanup: _
42//!     } = *data;
43//!
44//!     for statement in statements {
45//!         self.visit_statement(block, statement);
46//!     }
47//!
48//!     ...
49//! }
50//! ```
51//!
52//! Here we used `let BasicBlockData { <fields> } = *data` deliberately,
53//! rather than writing `data.statements` in the body. This is because if one
54//! adds a new field to `BasicBlockData`, one will be forced to revise this code,
55//! and hence one will (hopefully) invoke the correct visit methods (if any).
56//!
57//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
58//! That means you never write `..` to skip over fields, nor do you write `_`
59//! to skip over variants in a `match`.
60//!
61//! The only place that `_` is acceptable is to match a field (or
62//! variant argument) that does not require visiting, as in
63//! `is_cleanup` above.
64
65use crate::mir::*;
66use crate::ty::CanonicalUserTypeAnnotation;
67
68macro_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
72            // default behavior.
73
74            fn visit_body(
75                &mut self,
76                body: &$($mutability)? Body<'tcx>,
77            ) {
78                self.super_body(body);
79            }
80
81            extra_body_methods!($($mutability)?);
82
83            fn visit_basic_block_data(
84                &mut self,
85                block: BasicBlock,
86                data: & $($mutability)? BasicBlockData<'tcx>,
87            ) {
88                self.super_basic_block_data(block, data);
89            }
90
91            fn visit_source_scope_data(
92                &mut self,
93                scope_data: & $($mutability)? SourceScopeData<'tcx>,
94            ) {
95                self.super_source_scope_data(scope_data);
96            }
97
98            fn visit_statement(
99                &mut self,
100                statement: & $($mutability)? Statement<'tcx>,
101                location: Location,
102            ) {
103                self.super_statement(statement, location);
104            }
105
106            fn visit_assign(
107                &mut self,
108                place: & $($mutability)? Place<'tcx>,
109                rvalue: & $($mutability)? Rvalue<'tcx>,
110                location: Location,
111            ) {
112                self.super_assign(place, rvalue, location);
113            }
114
115            fn visit_terminator(
116                &mut self,
117                terminator: & $($mutability)? Terminator<'tcx>,
118                location: Location,
119            ) {
120                self.super_terminator(terminator, location);
121            }
122
123            fn visit_assert_message(
124                &mut self,
125                msg: & $($mutability)? AssertMessage<'tcx>,
126                location: Location,
127            ) {
128                self.super_assert_message(msg, location);
129            }
130
131            fn visit_rvalue(
132                &mut self,
133                rvalue: & $($mutability)? Rvalue<'tcx>,
134                location: Location,
135            ) {
136                self.super_rvalue(rvalue, location);
137            }
138
139            fn visit_operand(
140                &mut self,
141                operand: & $($mutability)? Operand<'tcx>,
142                location: Location,
143            ) {
144                self.super_operand(operand, location);
145            }
146
147            fn visit_ascribe_user_ty(
148                &mut self,
149                place: & $($mutability)? Place<'tcx>,
150                variance: $(& $mutability)? ty::Variance,
151                user_ty: & $($mutability)? UserTypeProjection,
152                location: Location,
153            ) {
154                self.super_ascribe_user_ty(place, variance, user_ty, location);
155            }
156
157            fn visit_coverage(
158                &mut self,
159                kind: & $($mutability)? coverage::CoverageKind,
160                location: Location,
161            ) {
162                self.super_coverage(kind, location);
163            }
164
165            fn visit_retag(
166                &mut self,
167                kind: $(& $mutability)? RetagKind,
168                place: & $($mutability)? Place<'tcx>,
169                location: Location,
170            ) {
171                self.super_retag(kind, place, location);
172            }
173
174            fn visit_place(
175                &mut self,
176                place: & $($mutability)? Place<'tcx>,
177                context: PlaceContext,
178                location: Location,
179            ) {
180                self.super_place(place, context, location);
181            }
182
183            visit_place_fns!($($mutability)?);
184
185            /// This is called for every constant in the MIR body and every `required_consts`
186            /// (i.e., including consts that have been dead-code-eliminated).
187            fn visit_const_operand(
188                &mut self,
189                constant: & $($mutability)? ConstOperand<'tcx>,
190                location: Location,
191            ) {
192                self.super_const_operand(constant, location);
193            }
194
195            fn visit_ty_const(
196                &mut self,
197                ct: $( & $mutability)? ty::Const<'tcx>,
198                location: Location,
199            ) {
200                self.super_ty_const(ct, location);
201            }
202
203            fn visit_span(
204                &mut self,
205                span: $(& $mutability)? Span,
206            ) {
207                self.super_span(span);
208            }
209
210            fn visit_source_info(
211                &mut self,
212                source_info: & $($mutability)? SourceInfo,
213            ) {
214                self.super_source_info(source_info);
215            }
216
217            fn visit_ty(
218                &mut self,
219                ty: $(& $mutability)? Ty<'tcx>,
220                _: TyContext,
221            ) {
222                self.super_ty(ty);
223            }
224
225            fn visit_user_type_projection(
226                &mut self,
227                ty: & $($mutability)? UserTypeProjection,
228            ) {
229                self.super_user_type_projection(ty);
230            }
231
232            fn visit_user_type_annotation(
233                &mut self,
234                index: UserTypeAnnotationIndex,
235                ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
236            ) {
237                self.super_user_type_annotation(index, ty);
238            }
239
240            fn visit_region(
241                &mut self,
242                region: $(& $mutability)? ty::Region<'tcx>,
243                _: Location,
244            ) {
245                self.super_region(region);
246            }
247
248            fn visit_args(
249                &mut self,
250                args: & $($mutability)? GenericArgsRef<'tcx>,
251                _: Location,
252            ) {
253                self.super_args(args);
254            }
255
256            fn visit_local_decl(
257                &mut self,
258                local: Local,
259                local_decl: & $($mutability)? LocalDecl<'tcx>,
260            ) {
261                self.super_local_decl(local, local_decl);
262            }
263
264            fn visit_var_debug_info(
265                &mut self,
266                var_debug_info: & $($mutability)* VarDebugInfo<'tcx>,
267            ) {
268                self.super_var_debug_info(var_debug_info);
269            }
270
271            fn visit_local(
272                &mut self,
273                local: $(& $mutability)? Local,
274                context: PlaceContext,
275                location: Location,
276            ) {
277                self.super_local(local, context, location)
278            }
279
280            fn visit_source_scope(
281                &mut self,
282                scope: $(& $mutability)? SourceScope,
283            ) {
284                self.super_source_scope(scope);
285            }
286
287            // The `super_xxx` methods comprise the default behavior and are
288            // not meant to be overridden.
289
290            fn super_body(
291                &mut self,
292                body: &$($mutability)? Body<'tcx>,
293            ) {
294                super_body!(self, body, $($mutability, true)?);
295            }
296
297            fn super_basic_block_data(
298                &mut self,
299                block: BasicBlock,
300                data: & $($mutability)? BasicBlockData<'tcx>)
301            {
302                let BasicBlockData {
303                    statements,
304                    terminator,
305                    is_cleanup: _
306                } = data;
307
308                let mut index = 0;
309                for statement in statements {
310                    let location = Location { block, statement_index: index };
311                    self.visit_statement(statement, location);
312                    index += 1;
313                }
314
315                if let Some(terminator) = terminator {
316                    let location = Location { block, statement_index: index };
317                    self.visit_terminator(terminator, location);
318                }
319            }
320
321            fn super_source_scope_data(
322                &mut self,
323                scope_data: & $($mutability)? SourceScopeData<'tcx>,
324            ) {
325                let SourceScopeData {
326                    span,
327                    parent_scope,
328                    inlined,
329                    inlined_parent_scope,
330                    local_data: _,
331                } = scope_data;
332
333                self.visit_span($(& $mutability)? *span);
334                if let Some(parent_scope) = parent_scope {
335                    self.visit_source_scope($(& $mutability)? *parent_scope);
336                }
337                if let Some((callee, callsite_span)) = inlined {
338                    let location = Location::START;
339
340                    self.visit_span($(& $mutability)? *callsite_span);
341
342                    let ty::Instance { def: callee_def, args: callee_args } = callee;
343                    match callee_def {
344                        ty::InstanceKind::Item(_def_id) => {}
345
346                        ty::InstanceKind::Intrinsic(_def_id)
347                        | ty::InstanceKind::VTableShim(_def_id)
348                        | ty::InstanceKind::ReifyShim(_def_id, _)
349                        | ty::InstanceKind::Virtual(_def_id, _)
350                        | ty::InstanceKind::ThreadLocalShim(_def_id)
351                        | ty::InstanceKind::ClosureOnceShim { call_once: _def_id, track_caller: _ }
352                        | ty::InstanceKind::ConstructCoroutineInClosureShim {
353                            coroutine_closure_def_id: _def_id,
354                            receiver_by_ref: _,
355                        }
356                        | ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, None)
357                        | ty::InstanceKind::DropGlue(_def_id, None) => {}
358
359                        ty::InstanceKind::FnPtrShim(_def_id, ty)
360                        | ty::InstanceKind::DropGlue(_def_id, Some(ty))
361                        | ty::InstanceKind::CloneShim(_def_id, ty)
362                        | ty::InstanceKind::FnPtrAddrShim(_def_id, ty)
363                        | ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, Some(ty)) => {
364                            // FIXME(eddyb) use a better `TyContext` here.
365                            self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
366                        }
367                    }
368                    self.visit_args(callee_args, location);
369                }
370                if let Some(inlined_parent_scope) = inlined_parent_scope {
371                    self.visit_source_scope($(& $mutability)? *inlined_parent_scope);
372                }
373            }
374
375            fn super_statement(
376                &mut self,
377                statement: & $($mutability)? Statement<'tcx>,
378                location: Location
379            ) {
380                let Statement { source_info, kind } = statement;
381
382                self.visit_source_info(source_info);
383                match kind {
384                    StatementKind::Assign(box (place, rvalue)) => {
385                        self.visit_assign(place, rvalue, location);
386                    }
387                    StatementKind::FakeRead(box (_, place)) => {
388                        self.visit_place(
389                            place,
390                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
391                            location
392                        );
393                    }
394                    StatementKind::SetDiscriminant { place, .. } => {
395                        self.visit_place(
396                            place,
397                            PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant),
398                            location
399                        );
400                    }
401                    StatementKind::Deinit(place) => {
402                        self.visit_place(
403                            place,
404                            PlaceContext::MutatingUse(MutatingUseContext::Deinit),
405                            location
406                        )
407                    }
408                    StatementKind::StorageLive(local) => {
409                        self.visit_local(
410                            $(& $mutability)? *local,
411                            PlaceContext::NonUse(NonUseContext::StorageLive),
412                            location
413                        );
414                    }
415                    StatementKind::StorageDead(local) => {
416                        self.visit_local(
417                            $(& $mutability)? *local,
418                            PlaceContext::NonUse(NonUseContext::StorageDead),
419                            location
420                        );
421                    }
422                    StatementKind::Retag(kind, place) => {
423                        self.visit_retag($(& $mutability)? *kind, place, location);
424                    }
425                    StatementKind::PlaceMention(place) => {
426                        self.visit_place(
427                            place,
428                            PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention),
429                            location
430                        );
431                    }
432                    StatementKind::AscribeUserType(box (place, user_ty), variance) => {
433                        self.visit_ascribe_user_ty(
434                            place,
435                            $(& $mutability)? *variance,
436                            user_ty,
437                            location
438                        );
439                    }
440                    StatementKind::Coverage(coverage) => {
441                        self.visit_coverage(
442                            coverage,
443                            location
444                        )
445                    }
446                    StatementKind::Intrinsic(box intrinsic) => {
447                        match intrinsic {
448                            NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location),
449                            NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
450                                src,
451                                dst,
452                                count
453                            }) => {
454                                self.visit_operand(src, location);
455                                self.visit_operand(dst, location);
456                                self.visit_operand(count, location);
457                            }
458                        }
459                    }
460                    StatementKind::ConstEvalCounter => {}
461                    StatementKind::Nop => {}
462                    StatementKind::BackwardIncompatibleDropHint { .. } => {}
463                }
464            }
465
466            fn super_assign(
467                &mut self,
468                place: &$($mutability)? Place<'tcx>,
469                rvalue: &$($mutability)? Rvalue<'tcx>,
470                location: Location
471            ) {
472                self.visit_place(
473                    place,
474                    PlaceContext::MutatingUse(MutatingUseContext::Store),
475                    location
476                );
477                self.visit_rvalue(rvalue, location);
478            }
479
480            fn super_terminator(
481                &mut self,
482                terminator: &$($mutability)? Terminator<'tcx>,
483                location: Location
484            ) {
485                let Terminator { source_info, kind } = terminator;
486
487                self.visit_source_info(source_info);
488                match kind {
489                    TerminatorKind::Goto { .. }
490                    | TerminatorKind::UnwindResume
491                    | TerminatorKind::UnwindTerminate(_)
492                    | TerminatorKind::CoroutineDrop
493                    | TerminatorKind::Unreachable
494                    | TerminatorKind::FalseEdge { .. }
495                    | TerminatorKind::FalseUnwind { .. } => {}
496
497                    TerminatorKind::Return => {
498                        // `return` logically moves from the return place `_0`. Note that the place
499                        // cannot be changed by any visitor, though.
500                        let $($mutability)? local = RETURN_PLACE;
501                        self.visit_local(
502                            $(& $mutability)? local,
503                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
504                            location,
505                        );
506
507                        assert_eq!(
508                            local,
509                            RETURN_PLACE,
510                            "`MutVisitor` tried to mutate return place of `return` terminator"
511                        );
512                    }
513
514                    TerminatorKind::SwitchInt { discr, targets: _ } => {
515                        self.visit_operand(discr, location);
516                    }
517
518                    TerminatorKind::Drop { place, target: _, unwind: _, replace: _ } => {
519                        self.visit_place(
520                            place,
521                            PlaceContext::MutatingUse(MutatingUseContext::Drop),
522                            location
523                        );
524                    }
525
526                    TerminatorKind::Call {
527                        func,
528                        args,
529                        destination,
530                        target: _,
531                        unwind: _,
532                        call_source: _,
533                        fn_span,
534                    } => {
535                        self.visit_span($(& $mutability)? *fn_span);
536                        self.visit_operand(func, location);
537                        for arg in args {
538                            self.visit_operand(&$($mutability)? arg.node, location);
539                        }
540                        self.visit_place(
541                            destination,
542                            PlaceContext::MutatingUse(MutatingUseContext::Call),
543                            location
544                        );
545                    }
546
547                    TerminatorKind::TailCall { func, args, fn_span } => {
548                        self.visit_span($(& $mutability)? *fn_span);
549                        self.visit_operand(func, location);
550                        for arg in args {
551                            self.visit_operand(&$($mutability)? arg.node, location);
552                        }
553                    },
554
555                    TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
556                        self.visit_operand(cond, location);
557                        self.visit_assert_message(msg, location);
558                    }
559
560                    TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
561                        self.visit_operand(value, location);
562                        self.visit_place(
563                            resume_arg,
564                            PlaceContext::MutatingUse(MutatingUseContext::Yield),
565                            location,
566                        );
567                    }
568
569                    TerminatorKind::InlineAsm {
570                        asm_macro: _,
571                        template: _,
572                        operands,
573                        options: _,
574                        line_spans: _,
575                        targets: _,
576                        unwind: _,
577                    } => {
578                        for op in operands {
579                            match op {
580                                InlineAsmOperand::In { value, .. } => {
581                                    self.visit_operand(value, location);
582                                }
583                                InlineAsmOperand::Out { place: Some(place), .. } => {
584                                    self.visit_place(
585                                        place,
586                                        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
587                                        location,
588                                    );
589                                }
590                                InlineAsmOperand::InOut { in_value, out_place, .. } => {
591                                    self.visit_operand(in_value, location);
592                                    if let Some(out_place) = out_place {
593                                        self.visit_place(
594                                            out_place,
595                                            PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
596                                            location,
597                                        );
598                                    }
599                                }
600                                InlineAsmOperand::Const { value }
601                                | InlineAsmOperand::SymFn { value } => {
602                                    self.visit_const_operand(value, location);
603                                }
604                                InlineAsmOperand::Out { place: None, .. }
605                                | InlineAsmOperand::SymStatic { def_id: _ }
606                                | InlineAsmOperand::Label { target_index: _ } => {}
607                            }
608                        }
609                    }
610                }
611            }
612
613            fn super_assert_message(
614                &mut self,
615                msg: & $($mutability)? AssertMessage<'tcx>,
616                location: Location
617            ) {
618                use crate::mir::AssertKind::*;
619                match msg {
620                    BoundsCheck { len, index } => {
621                        self.visit_operand(len, location);
622                        self.visit_operand(index, location);
623                    }
624                    Overflow(_, l, r) => {
625                        self.visit_operand(l, location);
626                        self.visit_operand(r, location);
627                    }
628                    OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
629                        self.visit_operand(op, location);
630                    }
631                    ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => {
632                        // Nothing to visit
633                    }
634                    MisalignedPointerDereference { required, found } => {
635                        self.visit_operand(required, location);
636                        self.visit_operand(found, location);
637                    }
638                }
639            }
640
641            fn super_rvalue(
642                &mut self,
643                rvalue: & $($mutability)? Rvalue<'tcx>,
644                location: Location
645            ) {
646                match rvalue {
647                    Rvalue::Use(operand) => {
648                        self.visit_operand(operand, location);
649                    }
650
651                    Rvalue::Repeat(value, ct) => {
652                        self.visit_operand(value, location);
653                        self.visit_ty_const($(&$mutability)? *ct, location);
654                    }
655
656                    Rvalue::ThreadLocalRef(_) => {}
657
658                    Rvalue::Ref(r, bk, path) => {
659                        self.visit_region($(& $mutability)? *r, location);
660                        let ctx = match bk {
661                            BorrowKind::Shared => PlaceContext::NonMutatingUse(
662                                NonMutatingUseContext::SharedBorrow
663                            ),
664                            BorrowKind::Fake(_) => PlaceContext::NonMutatingUse(
665                                NonMutatingUseContext::FakeBorrow
666                            ),
667                            BorrowKind::Mut { .. } =>
668                                PlaceContext::MutatingUse(MutatingUseContext::Borrow),
669                        };
670                        self.visit_place(path, ctx, location);
671                    }
672
673                    Rvalue::CopyForDeref(place) => {
674                        self.visit_place(
675                            place,
676                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
677                            location
678                        );
679                    }
680
681                    Rvalue::RawPtr(m, path) => {
682                        let ctx = match m {
683                            RawPtrKind::Mut => PlaceContext::MutatingUse(
684                                MutatingUseContext::RawBorrow
685                            ),
686                            RawPtrKind::Const => PlaceContext::NonMutatingUse(
687                                NonMutatingUseContext::RawBorrow
688                            ),
689                            RawPtrKind::FakeForPtrMetadata => PlaceContext::NonMutatingUse(
690                                NonMutatingUseContext::Inspect
691                            ),
692                        };
693                        self.visit_place(path, ctx, location);
694                    }
695
696                    Rvalue::Len(path) => {
697                        self.visit_place(
698                            path,
699                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
700                            location
701                        );
702                    }
703
704                    Rvalue::Cast(_cast_kind, operand, ty) => {
705                        self.visit_operand(operand, location);
706                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
707                    }
708
709                    Rvalue::BinaryOp(_bin_op, box(lhs, rhs)) => {
710                        self.visit_operand(lhs, location);
711                        self.visit_operand(rhs, location);
712                    }
713
714                    Rvalue::UnaryOp(_un_op, op) => {
715                        self.visit_operand(op, location);
716                    }
717
718                    Rvalue::Discriminant(place) => {
719                        self.visit_place(
720                            place,
721                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
722                            location
723                        );
724                    }
725
726                    Rvalue::NullaryOp(_op, ty) => {
727                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
728                    }
729
730                    Rvalue::Aggregate(kind, operands) => {
731                        let kind = &$($mutability)? **kind;
732                        match kind {
733                            AggregateKind::Array(ty) => {
734                                self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
735                            }
736                            AggregateKind::Tuple => {}
737                            AggregateKind::Adt(
738                                _adt_def,
739                                _variant_index,
740                                args,
741                                _user_args,
742                                _active_field_index
743                            ) => {
744                                self.visit_args(args, location);
745                            }
746                            AggregateKind::Closure(_, closure_args) => {
747                                self.visit_args(closure_args, location);
748                            }
749                            AggregateKind::Coroutine(_, coroutine_args) => {
750                                self.visit_args(coroutine_args, location);
751                            }
752                            AggregateKind::CoroutineClosure(_, coroutine_closure_args) => {
753                                self.visit_args(coroutine_closure_args, location);
754                            }
755                            AggregateKind::RawPtr(ty, _) => {
756                                self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
757                            }
758                        }
759
760                        for operand in operands {
761                            self.visit_operand(operand, location);
762                        }
763                    }
764
765                    Rvalue::ShallowInitBox(operand, ty) => {
766                        self.visit_operand(operand, location);
767                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
768                    }
769
770                    Rvalue::WrapUnsafeBinder(op, ty) => {
771                        self.visit_operand(op, location);
772                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
773                    }
774                }
775            }
776
777            fn super_operand(
778                &mut self,
779                operand: & $($mutability)? Operand<'tcx>,
780                location: Location
781            ) {
782                match operand {
783                    Operand::Copy(place) => {
784                        self.visit_place(
785                            place,
786                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
787                            location
788                        );
789                    }
790                    Operand::Move(place) => {
791                        self.visit_place(
792                            place,
793                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
794                            location
795                        );
796                    }
797                    Operand::Constant(constant) => {
798                        self.visit_const_operand(constant, location);
799                    }
800                }
801            }
802
803            fn super_ascribe_user_ty(
804                &mut self,
805                place: & $($mutability)? Place<'tcx>,
806                variance: $(& $mutability)? ty::Variance,
807                user_ty: & $($mutability)? UserTypeProjection,
808                location: Location)
809            {
810                self.visit_place(
811                    place,
812                    PlaceContext::NonUse(
813                        NonUseContext::AscribeUserTy($(* &$mutability *)? variance)
814                    ),
815                    location
816                );
817                self.visit_user_type_projection(user_ty);
818            }
819
820            fn super_coverage(
821                &mut self,
822                _kind: & $($mutability)? coverage::CoverageKind,
823                _location: Location
824            ) {
825            }
826
827            fn super_retag(
828                &mut self,
829                _kind: $(& $mutability)? RetagKind,
830                place: & $($mutability)? Place<'tcx>,
831                location: Location
832            ) {
833                self.visit_place(
834                    place,
835                    PlaceContext::MutatingUse(MutatingUseContext::Retag),
836                    location,
837                );
838            }
839
840            fn super_local_decl(
841                &mut self,
842                local: Local,
843                local_decl: & $($mutability)? LocalDecl<'tcx>
844            ) {
845                let LocalDecl {
846                    mutability: _,
847                    ty,
848                    user_ty,
849                    source_info,
850                    local_info: _,
851                } = local_decl;
852
853                self.visit_source_info(source_info);
854
855                self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl {
856                    local,
857                    source_info: *source_info,
858                });
859                if let Some(user_ty) = user_ty {
860                    for user_ty in & $($mutability)? user_ty.contents {
861                        self.visit_user_type_projection(user_ty);
862                    }
863                }
864            }
865
866            fn super_local(
867                &mut self,
868                _local: $(& $mutability)? Local,
869                _context: PlaceContext,
870                _location: Location,
871            ) {
872            }
873
874            fn super_var_debug_info(
875                &mut self,
876                var_debug_info: & $($mutability)? VarDebugInfo<'tcx>
877            ) {
878                let VarDebugInfo {
879                    name: _,
880                    source_info,
881                    composite,
882                    value,
883                    argument_index: _,
884                } = var_debug_info;
885
886                self.visit_source_info(source_info);
887                let location = Location::START;
888                if let Some(box VarDebugInfoFragment {
889                    ty,
890                    projection
891                }) = composite {
892                    self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
893                    for elem in projection {
894                        let ProjectionElem::Field(_, ty) = elem else { bug!() };
895                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
896                    }
897                }
898                match value {
899                    VarDebugInfoContents::Const(c) => self.visit_const_operand(c, location),
900                    VarDebugInfoContents::Place(place) =>
901                        self.visit_place(
902                            place,
903                            PlaceContext::NonUse(NonUseContext::VarDebugInfo),
904                            location
905                        ),
906                }
907            }
908
909            fn super_source_scope(&mut self, _scope: $(& $mutability)? SourceScope) {}
910
911            fn super_const_operand(
912                &mut self,
913                constant: & $($mutability)? ConstOperand<'tcx>,
914                location: Location
915            ) {
916                let ConstOperand {
917                    span,
918                    user_ty: _, // no visit method for this
919                    const_,
920                } = constant;
921
922                self.visit_span($(& $mutability)? *span);
923                match const_ {
924                    Const::Ty(_, ct) => self.visit_ty_const($(&$mutability)? *ct, location),
925                    Const::Val(_, ty) => {
926                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
927                    }
928                    Const::Unevaluated(_, ty) => {
929                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
930                    }
931                }
932            }
933
934            fn super_ty_const(
935                &mut self,
936                _ct: $(& $mutability)? ty::Const<'tcx>,
937                _location: Location,
938            ) {
939            }
940
941            fn super_span(&mut self, _span: $(& $mutability)? Span) {}
942
943            fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) {
944                let SourceInfo { span, scope } = source_info;
945
946                self.visit_span($(& $mutability)? *span);
947                self.visit_source_scope($(& $mutability)? *scope);
948            }
949
950            fn super_user_type_projection(&mut self, _ty: & $($mutability)? UserTypeProjection) {}
951
952            fn super_user_type_annotation(
953                &mut self,
954                _index: UserTypeAnnotationIndex,
955                ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
956            ) {
957                self.visit_span($(& $mutability)? ty.span);
958                self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
959            }
960
961            fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {}
962
963            fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {}
964
965            fn super_args(&mut self, _args: & $($mutability)? GenericArgsRef<'tcx>) {}
966
967            // Convenience methods
968
969            fn visit_location(
970                &mut self,
971                body: &$($mutability)? Body<'tcx>,
972                location: Location
973            ) {
974                let basic_block =
975                    & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
976                if basic_block.statements.len() == location.statement_index {
977                    if let Some(ref $($mutability)? terminator) = basic_block.terminator {
978                        self.visit_terminator(terminator, location)
979                    }
980                } else {
981                    let statement = & $($mutability)?
982                        basic_block.statements[location.statement_index];
983                    self.visit_statement(statement, location)
984                }
985            }
986        }
987    }
988}
989
990macro_rules! basic_blocks {
991    ($body:ident, mut, true) => {
992        $body.basic_blocks.as_mut()
993    };
994    ($body:ident, mut, false) => {
995        $body.basic_blocks.as_mut_preserves_cfg()
996    };
997    ($body:ident,) => {
998        $body.basic_blocks
999    };
1000}
1001
1002macro_rules! basic_blocks_iter {
1003    ($body:ident, mut, $invalidate:tt) => {
1004        basic_blocks!($body, mut, $invalidate).iter_enumerated_mut()
1005    };
1006    ($body:ident,) => {
1007        basic_blocks!($body,).iter_enumerated()
1008    };
1009}
1010
1011macro_rules! extra_body_methods {
1012    (mut) => {
1013        fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
1014            self.super_body_preserves_cfg(body);
1015        }
1016
1017        fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
1018            super_body!(self, body, mut, false);
1019        }
1020    };
1021    () => {};
1022}
1023
1024macro_rules! super_body {
1025    ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
1026        let span = $body.span;
1027        if let Some(coroutine) = &$($mutability)? $body.coroutine {
1028            if let Some(yield_ty) = $(& $mutability)? coroutine.yield_ty {
1029                $self.visit_ty(
1030                    yield_ty,
1031                    TyContext::YieldTy(SourceInfo::outermost(span))
1032                );
1033            }
1034            if let Some(resume_ty) = $(& $mutability)? coroutine.resume_ty {
1035                $self.visit_ty(
1036                    resume_ty,
1037                    TyContext::ResumeTy(SourceInfo::outermost(span))
1038                );
1039            }
1040        }
1041
1042        for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
1043            $self.visit_basic_block_data(bb, data);
1044        }
1045
1046        for scope in &$($mutability)? $body.source_scopes {
1047            $self.visit_source_scope_data(scope);
1048        }
1049
1050        $self.visit_ty(
1051            $(& $mutability)? $body.return_ty(),
1052            TyContext::ReturnTy(SourceInfo::outermost($body.span))
1053        );
1054
1055        for local in $body.local_decls.indices() {
1056            $self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]);
1057        }
1058
1059        #[allow(unused_macro_rules)]
1060        macro_rules! type_annotations {
1061            (mut) => ($body.user_type_annotations.iter_enumerated_mut());
1062            () => ($body.user_type_annotations.iter_enumerated());
1063        }
1064
1065        for (index, annotation) in type_annotations!($($mutability)?) {
1066            $self.visit_user_type_annotation(
1067                index, annotation
1068            );
1069        }
1070
1071        for var_debug_info in &$($mutability)? $body.var_debug_info {
1072            $self.visit_var_debug_info(var_debug_info);
1073        }
1074
1075        $self.visit_span($(& $mutability)? $body.span);
1076
1077        if let Some(required_consts) = &$($mutability)? $body.required_consts {
1078            for const_ in required_consts {
1079                let location = Location::START;
1080                $self.visit_const_operand(const_, location);
1081            }
1082        }
1083    }
1084}
1085
1086macro_rules! visit_place_fns {
1087    (mut) => {
1088        fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
1089
1090        fn super_place(
1091            &mut self,
1092            place: &mut Place<'tcx>,
1093            context: PlaceContext,
1094            location: Location,
1095        ) {
1096            self.visit_local(&mut place.local, context, location);
1097
1098            if let Some(new_projection) = self.process_projection(&place.projection, location) {
1099                place.projection = self.tcx().mk_place_elems(&new_projection);
1100            }
1101        }
1102
1103        fn process_projection<'a>(
1104            &mut self,
1105            projection: &'a [PlaceElem<'tcx>],
1106            location: Location,
1107        ) -> Option<Vec<PlaceElem<'tcx>>> {
1108            let mut projection = Cow::Borrowed(projection);
1109
1110            for i in 0..projection.len() {
1111                if let Some(&elem) = projection.get(i) {
1112                    if let Some(elem) = self.process_projection_elem(elem, location) {
1113                        // This converts the borrowed projection into `Cow::Owned(_)` and returns a
1114                        // clone of the projection so we can mutate and reintern later.
1115                        let vec = projection.to_mut();
1116                        vec[i] = elem;
1117                    }
1118                }
1119            }
1120
1121            match projection {
1122                Cow::Borrowed(_) => None,
1123                Cow::Owned(vec) => Some(vec),
1124            }
1125        }
1126
1127        fn process_projection_elem(
1128            &mut self,
1129            elem: PlaceElem<'tcx>,
1130            location: Location,
1131        ) -> Option<PlaceElem<'tcx>> {
1132            match elem {
1133                PlaceElem::Index(local) => {
1134                    let mut new_local = local;
1135                    self.visit_local(
1136                        &mut new_local,
1137                        PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
1138                        location,
1139                    );
1140
1141                    if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
1142                }
1143                PlaceElem::Field(field, ty) => {
1144                    let mut new_ty = ty;
1145                    self.visit_ty(&mut new_ty, TyContext::Location(location));
1146                    if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
1147                }
1148                PlaceElem::OpaqueCast(ty) => {
1149                    let mut new_ty = ty;
1150                    self.visit_ty(&mut new_ty, TyContext::Location(location));
1151                    if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
1152                }
1153                PlaceElem::Subtype(ty) => {
1154                    let mut new_ty = ty;
1155                    self.visit_ty(&mut new_ty, TyContext::Location(location));
1156                    if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
1157                }
1158                PlaceElem::UnwrapUnsafeBinder(ty) => {
1159                    let mut new_ty = ty;
1160                    self.visit_ty(&mut new_ty, TyContext::Location(location));
1161                    if ty != new_ty { Some(PlaceElem::UnwrapUnsafeBinder(new_ty)) } else { None }
1162                }
1163                PlaceElem::Deref
1164                | PlaceElem::ConstantIndex { .. }
1165                | PlaceElem::Subslice { .. }
1166                | PlaceElem::Downcast(..) => None,
1167            }
1168        }
1169    };
1170
1171    () => {
1172        fn visit_projection(
1173            &mut self,
1174            place_ref: PlaceRef<'tcx>,
1175            context: PlaceContext,
1176            location: Location,
1177        ) {
1178            self.super_projection(place_ref, context, location);
1179        }
1180
1181        fn visit_projection_elem(
1182            &mut self,
1183            place_ref: PlaceRef<'tcx>,
1184            elem: PlaceElem<'tcx>,
1185            context: PlaceContext,
1186            location: Location,
1187        ) {
1188            self.super_projection_elem(place_ref, elem, context, location);
1189        }
1190
1191        fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
1192            let mut context = context;
1193
1194            if !place.projection.is_empty() {
1195                if context.is_use() {
1196                    // ^ Only change the context if it is a real use, not a "use" in debuginfo.
1197                    context = if context.is_mutating_use() {
1198                        PlaceContext::MutatingUse(MutatingUseContext::Projection)
1199                    } else {
1200                        PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
1201                    };
1202                }
1203            }
1204
1205            self.visit_local(place.local, context, location);
1206
1207            self.visit_projection(place.as_ref(), context, location);
1208        }
1209
1210        fn super_projection(
1211            &mut self,
1212            place_ref: PlaceRef<'tcx>,
1213            context: PlaceContext,
1214            location: Location,
1215        ) {
1216            for (base, elem) in place_ref.iter_projections().rev() {
1217                self.visit_projection_elem(base, elem, context, location);
1218            }
1219        }
1220
1221        fn super_projection_elem(
1222            &mut self,
1223            _place_ref: PlaceRef<'tcx>,
1224            elem: PlaceElem<'tcx>,
1225            _context: PlaceContext,
1226            location: Location,
1227        ) {
1228            match elem {
1229                ProjectionElem::OpaqueCast(ty)
1230                | ProjectionElem::Subtype(ty)
1231                | ProjectionElem::Field(_, ty)
1232                | ProjectionElem::UnwrapUnsafeBinder(ty) => {
1233                    self.visit_ty(ty, TyContext::Location(location));
1234                }
1235                ProjectionElem::Index(local) => {
1236                    self.visit_local(
1237                        local,
1238                        PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
1239                        location,
1240                    );
1241                }
1242                ProjectionElem::Deref
1243                | ProjectionElem::Subslice { from: _, to: _, from_end: _ }
1244                | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ }
1245                | ProjectionElem::Downcast(_, _) => {}
1246            }
1247        }
1248    };
1249}
1250
1251make_mir_visitor!(Visitor,);
1252make_mir_visitor!(MutVisitor, mut);
1253
1254/// Extra information passed to `visit_ty` and friends to give context
1255/// about where the type etc appears.
1256#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
1257pub enum TyContext {
1258    LocalDecl {
1259        /// The index of the local variable we are visiting.
1260        local: Local,
1261
1262        /// The source location where this local variable was declared.
1263        source_info: SourceInfo,
1264    },
1265
1266    /// The inferred type of a user type annotation.
1267    UserTy(Span),
1268
1269    /// The return type of the function.
1270    ReturnTy(SourceInfo),
1271
1272    YieldTy(SourceInfo),
1273
1274    ResumeTy(SourceInfo),
1275
1276    /// A type found at some location.
1277    Location(Location),
1278}
1279
1280#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1281pub enum NonMutatingUseContext {
1282    /// Being inspected in some way, like loading a len.
1283    Inspect,
1284    /// Consumed as part of an operand.
1285    Copy,
1286    /// Consumed as part of an operand.
1287    Move,
1288    /// Shared borrow.
1289    SharedBorrow,
1290    /// A fake borrow.
1291    /// FIXME: do we need to distinguish shallow and deep fake borrows? In fact, do we need to
1292    /// distinguish fake and normal deep borrows?
1293    FakeBorrow,
1294    /// `&raw const`.
1295    RawBorrow,
1296    /// PlaceMention statement.
1297    ///
1298    /// This statement is executed as a check that the `Place` is live without reading from it,
1299    /// so it must be considered as a non-mutating use.
1300    PlaceMention,
1301    /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
1302    /// For example, the projection `x.y` is not marked as a mutation in these cases:
1303    /// ```ignore (illustrative)
1304    /// z = x.y;
1305    /// f(&x.y);
1306    /// ```
1307    Projection,
1308}
1309
1310#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1311pub enum MutatingUseContext {
1312    /// Appears as LHS of an assignment.
1313    Store,
1314    /// Appears on `SetDiscriminant`
1315    SetDiscriminant,
1316    /// Appears on `Deinit`
1317    Deinit,
1318    /// Output operand of an inline assembly block.
1319    AsmOutput,
1320    /// Destination of a call.
1321    Call,
1322    /// Destination of a yield.
1323    Yield,
1324    /// Being dropped.
1325    Drop,
1326    /// Mutable borrow.
1327    Borrow,
1328    /// `&raw mut`.
1329    RawBorrow,
1330    /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
1331    /// For example, the projection `x.y` is marked as a mutation in these cases:
1332    /// ```ignore (illustrative)
1333    /// x.y = ...;
1334    /// f(&mut x.y);
1335    /// ```
1336    Projection,
1337    /// Retagging, a "Stacked Borrows" shadow state operation
1338    Retag,
1339}
1340
1341#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1342pub enum NonUseContext {
1343    /// Starting a storage live range.
1344    StorageLive,
1345    /// Ending a storage live range.
1346    StorageDead,
1347    /// User type annotation assertions for NLL.
1348    AscribeUserTy(ty::Variance),
1349    /// The data of a user variable, for debug info.
1350    VarDebugInfo,
1351}
1352
1353#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1354pub enum PlaceContext {
1355    NonMutatingUse(NonMutatingUseContext),
1356    MutatingUse(MutatingUseContext),
1357    NonUse(NonUseContext),
1358}
1359
1360impl PlaceContext {
1361    /// Returns `true` if this place context represents a drop.
1362    #[inline]
1363    pub fn is_drop(self) -> bool {
1364        matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
1365    }
1366
1367    /// Returns `true` if this place context represents a borrow, excluding fake borrows
1368    /// (which are an artifact of borrowck and not actually borrows in runtime MIR).
1369    pub fn is_borrow(self) -> bool {
1370        matches!(
1371            self,
1372            PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
1373                | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
1374        )
1375    }
1376
1377    /// Returns `true` if this place context represents an address-of.
1378    pub fn is_address_of(self) -> bool {
1379        matches!(
1380            self,
1381            PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow)
1382                | PlaceContext::MutatingUse(MutatingUseContext::RawBorrow)
1383        )
1384    }
1385
1386    /// Returns `true` if this place context represents a storage live or storage dead marker.
1387    #[inline]
1388    pub fn is_storage_marker(self) -> bool {
1389        matches!(
1390            self,
1391            PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
1392        )
1393    }
1394
1395    /// Returns `true` if this place context represents a use that potentially changes the value.
1396    #[inline]
1397    pub fn is_mutating_use(self) -> bool {
1398        matches!(self, PlaceContext::MutatingUse(..))
1399    }
1400
1401    /// Returns `true` if this place context represents a use.
1402    #[inline]
1403    pub fn is_use(self) -> bool {
1404        !matches!(self, PlaceContext::NonUse(..))
1405    }
1406
1407    /// Returns `true` if this place context represents an assignment statement.
1408    pub fn is_place_assignment(self) -> bool {
1409        matches!(
1410            self,
1411            PlaceContext::MutatingUse(
1412                MutatingUseContext::Store
1413                    | MutatingUseContext::Call
1414                    | MutatingUseContext::AsmOutput,
1415            )
1416        )
1417    }
1418
1419    /// The variance of a place in the given context.
1420    pub fn ambient_variance(self) -> ty::Variance {
1421        use NonMutatingUseContext::*;
1422        use NonUseContext::*;
1423        match self {
1424            PlaceContext::MutatingUse(_) => ty::Invariant,
1425            PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
1426            PlaceContext::NonMutatingUse(
1427                Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | RawBorrow
1428                | Projection,
1429            ) => ty::Covariant,
1430            PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
1431        }
1432    }
1433}