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